How can I Resize a JScrollPane with JTable on it? - java

I created a JTable with some nice functions. My problem is, that it does not resize when I size the frame where it is on. Can someone help me with my Code so it does resize like it should? I alaready tryed some ideas of posts I found but it did not rly help me. So I have tryed to add the JPanel on another one with some Layout ideas. I have also tryed to use ComponentListeners and setSize on resizeaction.
Code:
public class TableyTable extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
public JTableHeader header;
public JTable table;
public JScrollPane scrollPane;
public JPopupMenu renamePopup;
public JTextField text;
public TableColumn column;
private boolean headerEditable = false;
private boolean tableEditable = false;
public static final Dimension SCREEN_SIZE = Toolkit.getDefaultToolkit().getScreenSize();
public static final int MIN_ROW_HEIGHT = (int)SCREEN_SIZE.getHeight()/36;
public static final int MIN_ROW_WIDTH = (int)SCREEN_SIZE.getWidth()/108;
public TableyTable(int row, int column) {
init(row, column);
}
public void init(int row, int column) {
table = new JTable(row, column) {
/**
*
*/
private static final long serialVersionUID = 1L;
#Override
public boolean isCellEditable(int row, int column) {
if (tableEditable) return true;
return false;
}
};
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.changeSelection(0, 0, false, false);
header = table.getTableHeader();
header.addMouseListener(new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent event) {
if (event.getClickCount() == 2 && headerEditable) {
editColumnAt(event.getPoint());
}
}
});
text = new JTextField();
text.setBorder(null);
text.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (headerEditable) renameColumn();
}
});
table.setRowSelectionAllowed(false);
table.setCellSelectionEnabled(true);
renamePopup = new JPopupMenu();
renamePopup.setBorder(new MatteBorder(0, 1, 1, 1, Color.DARK_GRAY));
renamePopup.add(text);
scrollPane = new JScrollPane( table );
scrollPane.setRowHeaderView(buildRowHeader(table));
table.setRowHeight(MIN_ROW_HEIGHT);
TableColumnModel cm = table.getColumnModel();
for(int i = 0; i < table.getColumnModel().getColumnCount(); i++)
cm.getColumn(i).setWidth(200);
table.setColumnModel(cm);
add(scrollPane);
}
public void setHeaderEditable(boolean b) {
headerEditable = b;
}
public boolean isHeaderEditable() {
return headerEditable;
}
public void setTableEditable(boolean b) {
tableEditable = b;
}
public boolean isTableEditable() {
return tableEditable;
}
private void editColumnAt(Point p) {
int columnIndex = header.columnAtPoint(p);
if (columnIndex != -1) {
column = header.getColumnModel().getColumn(columnIndex);
Rectangle columnRectangle = header.getHeaderRect(columnIndex);
text.setText(column.getHeaderValue().toString());
renamePopup.setPreferredSize(new Dimension(columnRectangle.width, columnRectangle.height - 1));
renamePopup.show(header, columnRectangle.x, 0);
text.requestFocusInWindow();
text.selectAll();
}
}
private void renameColumn() {
column.setHeaderValue(text.getText());
renamePopup.setVisible(false);
header.repaint();
}
private static JList<Object> buildRowHeader(JTable table) {
final Vector<String> headers = new Vector<String>();
for (int i = 0; i < table.getRowCount(); i++) {
String name = "";
if (i < 10) {
name += "0";
}
if (i < 100) {
name += "0";
}
name += i;
headers.add(name);
}
ListModel<Object> lm = new AbstractListModel<Object>() {
/**
*
*/
private static final long serialVersionUID = 1L;
public int getSize() {
return headers.size();
}
public Object getElementAt(int index) {
return headers.get(index);
}
};
final JList<Object> rowHeader = new JList<>(lm);
rowHeader.setOpaque(false);
rowHeader.setFixedCellWidth(TableyTable.MIN_ROW_HEIGHT);
MouseInputAdapter mouseAdapter = new MouseInputAdapter() {
Cursor oldCursor;
Cursor RESIZE_CURSOR = Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR);
int index = -1;
int oldY = -1;
#Override
public void mouseMoved(MouseEvent e) {
super.mouseMoved(e);
int previ = getLocationToIndex(new Point(e.getX(), e.getY() - 3));
int nexti = getLocationToIndex(new Point(e.getX(), e.getY() + 3));
if (previ != -1 && previ != nexti) {
if (!isResizeCursor()) {
oldCursor = rowHeader.getCursor();
rowHeader.setCursor(RESIZE_CURSOR);
index = previ;
}
} else if (isResizeCursor()) {
rowHeader.setCursor(oldCursor);
}
}
private int getLocationToIndex(Point point) {
int i = rowHeader.locationToIndex(point);
if (!rowHeader.getCellBounds(i, i).contains(point)) {
i = -1;
}
return i;
}
#Override
public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
if (isResizeCursor()) {
rowHeader.setCursor(oldCursor);
index = -1;
oldY = -1;
}
}
#Override
public void mouseDragged(MouseEvent e) {
super.mouseDragged(e);
if (isResizeCursor() && index != -1) {
int y = e.getY();
if (oldY != -1) {
int inc = y - oldY;
int oldRowHeight = table.getRowHeight(index);
int oldNextRowHeight = table.getRowHeight(index+1);
if (oldRowHeight > MIN_ROW_HEIGHT || inc > 0) {
int rowHeight = Math.max(MIN_ROW_HEIGHT, oldRowHeight + inc);
table.setRowHeight(index, rowHeight);
if (rowHeader.getModel().getSize() > index + 1) {
int rowHeight1 = table.getRowHeight(index + 1) - inc;
rowHeight1 = Math.max(MIN_ROW_HEIGHT, rowHeight1);
table.setRowHeight(index + 1, rowHeight1);
}
}
if (table.getRowCount()>index+1)
table.setRowHeight(1+index, oldNextRowHeight);
else System.out.println("HI");
}
oldY = y;
}
}
private boolean isResizeCursor() {
return rowHeader.getCursor() == RESIZE_CURSOR;
}
};
rowHeader.addMouseListener(mouseAdapter);
rowHeader.addMouseMotionListener(mouseAdapter);
rowHeader.addMouseWheelListener(mouseAdapter);
rowHeader.setCellRenderer(new RowHeaderRenderer(table));
rowHeader.setBackground(table.getBackground());
rowHeader.setForeground(table.getForeground());
return rowHeader;
}
static class RowHeaderRenderer extends JLabel implements ListCellRenderer<Object> {
/**
*
*/
private static final long serialVersionUID = 1L;
private JTable table;
RowHeaderRenderer(JTable table) {
this.table = table;
JTableHeader header = this.table.getTableHeader();
setOpaque(true);
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
setHorizontalAlignment(CENTER);
setForeground(header.getForeground());
setBackground(header.getBackground());
setFont(header.getFont());
setDoubleBuffered(true);
}
public Component getListCellRendererComponent(JList<?> list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
setText((value == null) ? "" : value.toString());
setPreferredSize(null);
setPreferredSize(new Dimension((int) getPreferredSize().getWidth(), table.getRowHeight(index)));
list.firePropertyChange("cellRenderer", 0, 1);
return this;
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Tabley");
TableyTable table = new TableyTable(1000, 18278);
table.setHeaderEditable(true);
table.setTableEditable(true);
frame.add(table);
frame.setSize(new Dimension(700, 500));
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

As in the tutorial described, you need to set a LayoutManager and add the JScrollPane accordingly:
setLayout(new BorderLayout());
add(scrollPane,BorderLayout.CENTER);

Related

Issue when putting a JLabel inside a Swing table

I'm trying to put a JLabel inside my Swing JTable but what I get is apparently the name of the object instead:
This is the class I used to load the JLabel into my table:
/**
* Main Class.
*/
public class Test extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private MyTable tableDest;
private MyTable tableSource;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
Test frame = new Test();
frame.setVisible(true);
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
* #throws Exception
*/
public Test() throws Exception {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JSplitPane splitPane = new JSplitPane();
splitPane.setResizeWeight(0.5);
contentPane.add(splitPane, BorderLayout.CENTER);
tableSource = new MyTable(true);
splitPane.setRightComponent(tableSource);
tableDest = new MyTable(false);
splitPane.setLeftComponent(tableDest);
TransferHandler transferHandler = new MyTransferHandler();
tableSource.setDragEnabled(true);
tableSource.setTransferHandler(transferHandler);
tableSource.setDropMode(DropMode.ON);
tableDest.setDragEnabled(true);
tableDest.setTransferHandler(transferHandler);
tableDest.setDropMode(DropMode.ON);
}
}
/**
* Class for The Table
*/
class MyTable extends JTable {
private static final long serialVersionUID = 1L;
public MyTable(boolean withData) throws Exception {
this( new MyTableModel(withData));
}
public MyTable(MyTableModel tableModel) {
super(tableModel);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
#Override
public MyTableModel getModel() {
return (MyTableModel)super.getModel();
}
}
/**
* Class for The JPanel import into The table
*/
class MyTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private JLabel[] dataSource = new JLabel[16];
public MyTableModel(boolean fill) {
if(fill) {
for(int i = 0; i < dataSource.length; i++) {
dataSource[i] = new JLabel("<html>Text color: <font color='red'>red</font></html>");
}
}
}
#Override
public int getRowCount() {
return 4;
}
#Override
public int getColumnCount() {
return 4;
}
#Override
public Object getValueAt(int row, int col) {
int index = getIndex(row, col);
return dataSource[index];
}
#Override
public void setValueAt(Object aValue, int row, int col) {
int index = getIndex(row, col);
dataSource[index] = (JLabel)aValue;
}
#Override
public Class<?> getColumnClass(int col) {
return JLabel.class;
}
public void removeAt(int row, int col) {
int index = getIndex(row, col);
dataSource[index] = null;
fireTableCellUpdated(row, col);
}
private int getIndex(int row, int col) {
return row*4 + col;
}
}
/**
* Class for the drag'n drop Stuff
*/
class MyTransferHandler extends TransferHandler {
private static final long serialVersionUID = 1L;
#Override
public int getSourceActions(JComponent comp) {
return MOVE;
}
int selectedRow;
int selectedCol;
#Override
public Transferable createTransferable(JComponent comp) {
System.out.println("createTransferable");
MyTable table = (MyTable)comp;
selectedRow = table.getSelectedRow();
selectedCol = table.getSelectedColumn();
String text = (String) table.getValueAt(selectedRow, selectedCol);
System.out.println("DND init for: " + text);
return new StringSelection(text);
}
#Override
public void exportDone(JComponent comp, Transferable trans, int action) {
System.out.println("exportDone");
if (action == MOVE) {
MyTable table = (MyTable)comp;
table.getModel().removeAt(selectedRow, selectedCol);
}
}
#Override
public boolean canImport(TransferSupport support) {
//System.out.println("canImport");
return support.isDrop();
}
#Override
public boolean importData(TransferSupport support) {
System.out.println("importData");
if(canImport(support)) { //to prevent from paste's
DropLocation dl = support.getDropLocation();
Point dropPoint = dl.getDropPoint();
String data;
try {
data = (String)support.getTransferable().getTransferData(DataFlavor.stringFlavor);
System.out.println("DND received: " + data);
} catch (UnsupportedFlavorException | IOException e) {
return false;
}
MyTable table = (MyTable)support.getComponent();
int row = table.rowAtPoint(dropPoint);
int col = table.columnAtPoint(dropPoint);
MyTableModel model = table.getModel();
Object currentValue = model.getValueAt(row, col);
if(currentValue == null) { //if there's currently no value on that cell
model.setValueAt(data, row, col);
model.fireTableCellUpdated(row, col);
return true;
}
}
return false;
}
}
What am I doing wrong? It's not supposed to display a JPanel instead of this text.
I'm trying to put a JLabel inside my Swing Table but what I get is apparentely the Name of the object instead.
JLabel is the default component for a cell in a JTable. I assume you added a JLabel to the default one, which caused its toString method to be invoked and displayed in the default label.
Here I created a new JTable and put your String in all the cells:
public class Test extends JFrame {
static String data = "<html>Text color: <font color='red'>red</font></html>";
static int size = 4;
public Test() {
JTable table = new JTable(size, size);
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
table.getModel().setValueAt(data, i, j);
}
}
add(table);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
public static void main(String[] args) {
new Test();
}
}

How to add a table, with one row made of JComboboxes, on top an existing JTable

I am trying to add a one row JTable on top of an existing JTable which is usually created dynamically and which changes its data model quite often.
As you can see the yellow area represents just a row counter and It has been created using this source
The yellow column, therefore has been attached to the main table using the following code:
JTable rowTable = new RowNumberTable(table);
scrollTable.setRowHeaderView(rowTable);
The table columns A, B, C, and so on, if clicked, sort the JTable accordingly and this feature should be maintained (I do not want to put the JCombobox in the table header unless there is a clever way of doing both things).
My aim is to create a JTable with one row (See red row) which has as many columns as the main JTable
EDIT
Here there is the SSCCE
I would like to put JComboBoxes on top of A,B,C,D.....
The class that renders the JComboBoxes is ColumnJComboBoxTable which is called in TableDemo as follow:
//Column JCombobox
JTable columnTable = new ColumnJComboBoxTable(table);
scrollTable.setColumnHeaderView(columnTable);
Right now it is not working as I want (Well, It is not working at all)
Buttons at the top add and remove columns. Therefore if a column is deleted the respective JComboBox must be deleted too.
CODE
TableDemo
package com.table;
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.AbstractAction;
public class TableDemo extends JFrame
{
private static final long serialVersionUID = 1L;
public TableDemo()
{
super("TableDemo");
Object[][] data =
{
{"0","1","2","3","4","5","6","7","8","9","10"},
{"0","1","2","3","4","5","6","7","8","9","10"},
{"0","1","2","3","4","5","6","7","8","9","10"},
{"0","1","2","3","4","5","6","7","8","9","10"},
{"0","1","2","3","4","5","6","7","8","9","10"},
{"0","1","2","3","4","5","6","7","8","9","10"},
{"0","1","2","3","4","5","6","7","8","9","10"},
{"0","1","2","3","4","5","6","7","8","9","10"},
{"0","1","2","3","4","5","6","7","8","9","10"},
{"0","1","2","3","4","5","6","7","8","9","10"},
{"0","1","2","3","4","5","6","7","8","9","10"},
{"0","1","2","3","4","5","6","7","8","9","10"},
{"0","1","2","3","4","5","6","7","8","9","10"},
{"0","1","2","3","4","5","6","7","8","9","10"},
};
String[] columnNames =
{
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
};
final JTable table = new JTable(data, columnNames);
new JPopupMenu();
final JToolBar toolBar = new JToolBar();
final XTableColumnModel columnModel = new XTableColumnModel();
table.setColumnModel(columnModel);
table.createDefaultColumnsFromModel();
toolBar.add(new JButton(new AbstractAction("ALL") {
/**
*
*/
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
columnModel.setAllColumnsVisible();
}
}));
toolBar.add(new JButton(new AbstractAction("Column 0") {
/**
*
*/
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
TableColumn column = columnModel.getColumnByModelIndex(0);
boolean visible = columnModel.isColumnVisible(column);
columnModel.setColumnVisible(column, !visible);
}
}));
toolBar.add(new JButton(new AbstractAction("Column 1") {
/**
*
*/
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
TableColumn column = columnModel.getColumnByModelIndex(1);
boolean visible = columnModel.isColumnVisible(column);
columnModel.setColumnVisible(column, !visible);
}
}));
toolBar.add(new JButton(new AbstractAction("Column 2") {
/**
*
*/
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
TableColumn column = columnModel.getColumnByModelIndex(2);
boolean visible = columnModel.isColumnVisible(column);
columnModel.setColumnVisible(column, !visible);
}
}));
toolBar.add(new JButton(new AbstractAction("Column 3") {
/**
*
*/
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
TableColumn column = columnModel.getColumnByModelIndex(3);
boolean visible = columnModel.isColumnVisible(column);
columnModel.setColumnVisible(column, !visible);
}
}));
toolBar.add(new JButton(new AbstractAction("Column 4") {
/**
*
*/
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
TableColumn column = columnModel.getColumnByModelIndex(4);
boolean visible = columnModel.isColumnVisible(column);
columnModel.setColumnVisible(column, !visible);
}
}));
toolBar.add(new JButton(new AbstractAction("Column 5") {
/**
*
*/
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
TableColumn column = columnModel.getColumnByModelIndex(5);
boolean visible = columnModel.isColumnVisible(column);
columnModel.setColumnVisible(column, !visible);
}
}));
toolBar.add(new JButton(new AbstractAction("Column 6") {
/**
*
*/
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
TableColumn column = columnModel.getColumnByModelIndex(6);
boolean visible = columnModel.isColumnVisible(column);
columnModel.setColumnVisible(column, !visible);
}
}));
toolBar.add(new JButton(new AbstractAction("Column 7") {
/**
*
*/
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
TableColumn column = columnModel.getColumnByModelIndex(7);
boolean visible = columnModel.isColumnVisible(column);
columnModel.setColumnVisible(column, !visible);
}
}));
toolBar.add(new JButton(new AbstractAction("Column 8") {
/**
*
*/
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
TableColumn column = columnModel.getColumnByModelIndex(8);
boolean visible = columnModel.isColumnVisible(column);
columnModel.setColumnVisible(column, !visible);
}
}));
toolBar.add(new JButton(new AbstractAction("Column 9") {
/**
*
*/
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
TableColumn column = columnModel.getColumnByModelIndex(9);
boolean visible = columnModel.isColumnVisible(column);
columnModel.setColumnVisible(column, !visible);
}
}));
toolBar.add(new JButton(new AbstractAction("Column 10") {
/**
*
*/
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
TableColumn column = columnModel.getColumnByModelIndex(10);
boolean visible = columnModel.isColumnVisible(column);
columnModel.setColumnVisible(column, !visible);
}
}));
//Row number
table.setFillsViewportHeight(true);
JScrollPane scrollTable = new JScrollPane(table,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollTable.setViewportView(table);
JTable rowTable = new RowNumberTable(table);
scrollTable.setRowHeaderView(rowTable);
scrollTable.setCorner(JScrollPane.UPPER_LEFT_CORNER, rowTable.getTableHeader());
//Column JCombobox
JTable columnTable = new ColumnJComboBoxTable(table);
scrollTable.setColumnHeaderView(columnTable);
getContentPane().add(toolBar, BorderLayout.NORTH);
getContentPane().add(scrollTable, BorderLayout.CENTER);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public static void main(String[] args)
{
TableDemo frame = new TableDemo();
frame.pack();
frame.repaint();
frame.setVisible(true);
}
}
XTableColumnModel
The table model has been borrowed here
package com.table;
import javax.swing.table.*;
import java.util.Vector;
import java.util.Enumeration;
public class XTableColumnModel extends DefaultTableColumnModel {
private static final long serialVersionUID = 1L;
protected Vector allTableColumns = new Vector();
XTableColumnModel() {
}
public void setColumnVisible(TableColumn column, boolean visible) {
if(!visible) {
super.removeColumn(column);
}
else
{
int noVisibleColumns = tableColumns.size();
int noInvisibleColumns = allTableColumns.size();
int visibleIndex = 0;
for(int invisibleIndex = 0; invisibleIndex < noInvisibleColumns; ++invisibleIndex) {
TableColumn visibleColumn = (visibleIndex < noVisibleColumns ? (TableColumn)tableColumns.get(visibleIndex) : null);
TableColumn testColumn = (TableColumn)allTableColumns.get(invisibleIndex);
if(testColumn == column) {
if(visibleColumn != column) {
super.addColumn(column);
super.moveColumn(tableColumns.size() - 1, visibleIndex);
}
return;
}
if(testColumn == visibleColumn) {
++visibleIndex;
}
}
}
}
public void setAllColumnsVisible() {
int noColumns = allTableColumns.size();
for(int columnIndex = 0; columnIndex < noColumns; ++columnIndex) {
TableColumn visibleColumn = (columnIndex < tableColumns.size() ? (TableColumn)tableColumns.get(columnIndex) : null);
TableColumn invisibleColumn = (TableColumn)allTableColumns.get(columnIndex);
if(visibleColumn != invisibleColumn) {
super.addColumn(invisibleColumn);
super.moveColumn(tableColumns.size() - 1, columnIndex);
}
}
}
public TableColumn getColumnByModelIndex(int modelColumnIndex) {
for (int columnIndex = 0; columnIndex < allTableColumns.size(); ++columnIndex) {
TableColumn column = (TableColumn)allTableColumns.elementAt(columnIndex);
if(column.getModelIndex() == modelColumnIndex) {
return column;
}
}
return null;
}
public boolean isColumnVisible(TableColumn aColumn) {
return (tableColumns.indexOf(aColumn) >= 0);
}
public void addColumn(TableColumn column) {
allTableColumns.addElement(column);
super.addColumn(column);
}
public void removeColumn(TableColumn column) {
int allColumnsIndex = allTableColumns.indexOf(column);
if(allColumnsIndex != -1) {
allTableColumns.removeElementAt(allColumnsIndex);
}
super.removeColumn(column);
}
public void moveColumn(int oldIndex, int newIndex) {
if ((oldIndex < 0) || (oldIndex >= getColumnCount()) ||
(newIndex < 0) || (newIndex >= getColumnCount()))
throw new IllegalArgumentException("moveColumn() - Index out of range");
TableColumn fromColumn = (TableColumn) tableColumns.get(oldIndex);
TableColumn toColumn = (TableColumn) tableColumns.get(newIndex);
int allColumnsOldIndex = allTableColumns.indexOf(fromColumn);
int allColumnsNewIndex = allTableColumns.indexOf(toColumn);
if(oldIndex != newIndex) {
allTableColumns.removeElementAt(allColumnsOldIndex);
allTableColumns.insertElementAt(fromColumn, allColumnsNewIndex);
}
super.moveColumn(oldIndex, newIndex);
}
public int getColumnCount(boolean onlyVisible) {
Vector columns = (onlyVisible ? tableColumns : allTableColumns);
return columns.size();
}
public Enumeration getColumns(boolean onlyVisible) {
Vector columns = (onlyVisible ? tableColumns : allTableColumns);
return columns.elements();
}
public int getColumnIndex(Object identifier, boolean onlyVisible) {
if (identifier == null) {
throw new IllegalArgumentException("Identifier is null");
}
Vector columns = (onlyVisible ? tableColumns : allTableColumns);
int noColumns = columns.size();
TableColumn column;
for(int columnIndex = 0; columnIndex < noColumns; ++columnIndex) {
column = (TableColumn)columns.get(columnIndex);
if(identifier.equals(column.getIdentifier()))
return columnIndex;
}
throw new IllegalArgumentException("Identifier not found");
}
public TableColumn getColumn(int columnIndex, boolean onlyVisible) {
return (TableColumn)tableColumns.elementAt(columnIndex);
}
}
RowNumberTable
package com.table;
import java.awt.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class RowNumberTable extends JTable
implements ChangeListener, PropertyChangeListener, TableModelListener
{
private static final long serialVersionUID = -3837585325898676144L;
private JTable main;
public RowNumberTable(JTable table)
{
main = table;
main.addPropertyChangeListener( this );
main.getModel().addTableModelListener( this );
setFocusable( false );
setAutoCreateColumnsFromModel( false );
setSelectionModel( main.getSelectionModel() );
TableColumn column = new TableColumn();
column.setHeaderValue(" ");
addColumn( column );
column.setCellRenderer(new RowNumberRenderer());
getColumnModel().getColumn(0).setPreferredWidth(50);
setPreferredScrollableViewportSize(getPreferredSize());
}
#Override
public void addNotify()
{
super.addNotify();
Component c = getParent();
// Keep scrolling of the row table in sync with the main table.
if (c instanceof JViewport)
{
JViewport viewport = (JViewport)c;
viewport.addChangeListener( this );
}
}
#Override
public int getRowCount()
{
return main.getRowCount();
}
#Override
public int getRowHeight(int row)
{
int rowHeight = main.getRowHeight(row);
if (rowHeight != super.getRowHeight(row))
{
super.setRowHeight(row, rowHeight);
}
return rowHeight;
}
#Override
public Object getValueAt(int row, int column)
{
return Integer.toString(row + 1);
}
#Override
public boolean isCellEditable(int row, int column)
{
return false;
}
#Override
public void setValueAt(Object value, int row, int column) {}
public void stateChanged(ChangeEvent e)
{
// Keep the scrolling of the row table in sync with main table
JViewport viewport = (JViewport) e.getSource();
JScrollPane scrollPane = (JScrollPane)viewport.getParent();
scrollPane.getVerticalScrollBar().setValue(viewport.getViewPosition().y);
viewport.setBackground(Color.WHITE);
}
public void propertyChange(PropertyChangeEvent e)
{
// Keep the row table in sync with the main table
if ("selectionModel".equals(e.getPropertyName()))
{
setSelectionModel( main.getSelectionModel() );
}
if ("rowHeight".equals(e.getPropertyName()))
{
repaint();
}
if ("model".equals(e.getPropertyName()))
{
main.getModel().addTableModelListener( this );
revalidate();
}
}
#Override
public void tableChanged(TableModelEvent e)
{
revalidate();
}
/*
* Attempt to mimic the table header renderer
*/
private static class RowNumberRenderer extends DefaultTableCellRenderer
{
/**
*
*/
private static final long serialVersionUID = 6579115025835194953L;
public RowNumberRenderer()
{
setHorizontalAlignment(JLabel.CENTER);
}
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
if (table != null)
{
JTableHeader header = table.getTableHeader();
if (header != null)
{
setForeground(header.getForeground());
setBackground(header.getBackground());
setFont(header.getFont());
}
}
if (isSelected)
{
setFont( getFont().deriveFont(Font.ITALIC) );
}
setText((value == null) ? "" : value.toString());
//setBorder(UIManager.getBorder("TableHeader.cellBorder"));
return this;
}
}
}
ColumnJComboBoxTable
package com.table;
import java.awt.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class ColumnJComboBoxTable extends JTable implements ChangeListener,PropertyChangeListener, TableModelListener
{
private static final long serialVersionUID = -3837585325898676144L;
private JTable main;
public ColumnJComboBoxTable(JTable table)
{
main = table;
main.addPropertyChangeListener( this );
main.getModel().addTableModelListener( this );
setFocusable( false );
setAutoCreateColumnsFromModel( false );
setSelectionModel( main.getSelectionModel() );
for(int i =0; i<main.getModel().getColumnCount();i++)
{
TableColumn column = new TableColumn();
column.setHeaderValue(i);
addColumn( column );
getColumnModel().getColumn(i).setPreferredWidth(50);
column.setCellRenderer(new ColumnJComboBoxRenderer());
column.setHeaderRenderer(new ColumnJComboBoxRenderer());
}
setPreferredScrollableViewportSize(getPreferredSize());
}
#Override
public void addNotify()
{
super.addNotify();
Component c = getParent();
// Keep scrolling of the row table in sync with the main table.
if (c instanceof JViewport)
{
JViewport viewport = (JViewport)c;
viewport.addChangeListener( this );
}
}
#Override
public int getColumnCount()
{
return main.getColumnCount();
}
#Override
public int getRowHeight(int row)
{
int rowHeight = main.getRowHeight(row);
if (rowHeight != super.getRowHeight(row))
{
super.setRowHeight(row, rowHeight);
}
return rowHeight;
}
/*
* No model is being used for this table so just use the row number
* as the value of the cell.
*/
#Override
public Object getValueAt(int row, int column)
{
return Integer.toString(column + 1);
}
/*
* Don't edit data in the main TableModel by mistake
*/
#Override
public boolean isCellEditable(int row, int column)
{
return false;
}
/*
* Do nothing since the table ignores the model
*/
#Override
public void setValueAt(Object value, int row, int column) {}
//
// Implement the ChangeListener
//
public void stateChanged(ChangeEvent e)
{
// Keep the scrolling of the row table in sync with main table
JViewport viewport = (JViewport) e.getSource();
JScrollPane scrollPane = (JScrollPane)viewport.getParent();
scrollPane.getHorizontalScrollBar().setValue(viewport.getViewPosition().x);
}
//
// Implement the PropertyChangeListener
//
public void propertyChange(PropertyChangeEvent e)
{
// Keep the row table in sync with the main table
if ("selectionModel".equals(e.getPropertyName()))
{
setSelectionModel( main.getSelectionModel() );
}
if ("rowHeight".equals(e.getPropertyName()))
{
repaint();
}
if ("model".equals(e.getPropertyName()))
{
main.getModel().addTableModelListener( this );
revalidate();
}
}
//
// Implement the TableModelListener
//
#Override
public void tableChanged(TableModelEvent e)
{
revalidate();
}
/*
* Attempt to mimic the table header renderer
*/
private static class ColumnJComboBoxRenderer extends DefaultTableCellRenderer
{
/**
*
*/
private static final long serialVersionUID = 6579115025835194953L;
public ColumnJComboBoxRenderer()
{
setHorizontalAlignment(JLabel.HORIZONTAL);
}
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
{
if (table != null)
{
JTableHeader header = table.getTableHeader();
if (header != null)
{
setForeground(header.getForeground());
setBackground(header.getBackground());
setFont(header.getFont());
}
}
if (isSelected)
{
setFont( getFont().deriveFont(Font.ITALIC) );
}
setText((value == null) ? "" : value.toString());
return this;
}
}
}
Anyone's help would be highly appreciated
Thanks
Thanks to #mKorbel for the help
Here the code of a solution
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class TableFilterRow implements TableColumnModelListener
{
private JTable table;
private JPanel filterRow;
public TableFilterRow(JTable table,JPanel filterRow)
{
this.table = table;
this.filterRow=filterRow;
table.setPreferredScrollableViewportSize(table.getPreferredSize());
table.getColumnModel().addColumnModelListener(this);
table.columnMarginChanged(new ChangeEvent(table.getColumnModel()));
}
#Override
public void columnMarginChanged(ChangeEvent e)
{
TableColumnModel tcm = table.getColumnModel();
int columns = tcm.getColumnCount();
for (int i = 0; i < columns; i++)
{
JComboBox<?> comboBox = (JComboBox<?>) filterRow.getComponent(i);
Dimension d = comboBox.getPreferredSize();
d.width = tcm.getColumn(i).getWidth();
comboBox.setPreferredSize(d);
}
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
filterRow.revalidate();
}
});
}
#Override
public void columnMoved(TableColumnModelEvent e)
{
Component moved = filterRow.getComponent(e.getFromIndex());
filterRow.remove(e.getFromIndex());
filterRow.add(moved, e.getToIndex());
filterRow.validate();
}
#Override
public void columnAdded(TableColumnModelEvent e)
{
}
#Override
public void columnRemoved(TableColumnModelEvent e)
{
}
#Override
public void columnSelectionChanged(ListSelectionEvent e)
{
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setLayout(new BorderLayout());
JTable table = new JTable(3, 5);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
table.columnMarginChanged(new ChangeEvent(table.getColumnModel()));
ComboFields[] comboFields = ComboFields.values();
JScrollPane scrollPane = new JScrollPane(table);
frame.add(scrollPane, BorderLayout.CENTER);
JPanel filterRow = new JPanel();
filterRow.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
for (int i = 0; i < table.getColumnCount(); i++)
{
filterRow.add(new JComboBox<ComboFields>(comboFields));
}
new TableFilterRow(table, filterRow);
frame.add(filterRow, BorderLayout.NORTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private enum ComboFields{
VALUE_0(0),
VALUE_1(1),
VALUE_2(2),
VALUE_3(3),
VALUE_4(4),
VALUE_5(5);
// Internal state
private int fieldNumber;
private ComboFields(final int fieldNumber)
{
this.setFieldNumber(fieldNumber);
}
#SuppressWarnings("unused")
public int getFieldNumber() {
return fieldNumber;
}
public void setFieldNumber(int fieldNumber)
{
this.fieldNumber = fieldNumber;
}
}
}

Swing blurred drag image

I have a simple task to implement, it works quite ok, but I am facing a very tricky issue regarding custom drag images in Swing.
The idea behind the task is just to allow the user to perform some DND between a list component and a text component, but during the drag operation to display following the mouse the exact same drawing as the renderer inside the list.
For this I use the cell renderer for the selected elements in the list and paint it over a temporary image. Then send this image to the TransferHandler and everything is fine. The problem is evident when I modify the size of the overall component and make it larger. After a certain extent, the picture that is draw no longer appears correct, but instead it has some gradient applied to it, making the content difficult to read. Following is a snippet of code that reproduces the issue:
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.DropMode;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class BasicTextListDND {
private JList<String> makeList() {
DefaultListModel<String> m = new DefaultListModel<String>();
for(int i = 0; i<10; i++) {
m.addElement("Element "+i);
}
JList<String> list = new JList<String>(m);
list.setTransferHandler(new BasicListTransferHandler());
list.setDropMode(DropMode.ON_OR_INSERT);
list.setDragEnabled(true);
list.setCellRenderer(new DefaultListCellRenderer() {
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 1L;
/** {#inheritDoc} */
public Component getListCellRendererComponent(JList<?> list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
Component listCellRendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (cellHasFocus == false && isSelected == false) {
if (index % 2 == 0) {
listCellRendererComponent.setBackground(Color.RED);
} else if (index % 3==0) {
listCellRendererComponent.setBackground(Color.GREEN);
} else {
listCellRendererComponent.setBackground(Color.BLUE);
}
}
return listCellRendererComponent;
}
});
return list;
}
private JTextArea makeTextArea() {
JTextArea textArea = new JTextArea("Drag here from JList!");
return textArea;
}
public JComponent makeUI() {
JPanel panel = new JPanel(new GridLayout(2,1));
panel.add(new JScrollPane(makeTextArea()));
panel.add(new JScrollPane(makeList()));
return panel;
}
private static void createAndShowGUI() {
JFrame f = new JFrame("BasicDnD");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BasicTextListDND app = new BasicTextListDND();
JComponent appContent = app.makeUI();
f.setContentPane(appContent);
f.setSize(600, 320);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
}
/**
*
*/
public class BasicListTransferHandler extends TransferHandler {
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 1L;
#Override
public boolean canImport(TransferHandler.TransferSupport info) {
if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
JList.DropLocation dl = (JList.DropLocation)info.getDropLocation();
if (dl.getIndex() == -1) {
return false;
}
return true;
}
#Override
public int getSourceActions(JComponent c) {
BufferedImage dragImage = makeImageFromString(c);
if (dragImage != null) {
setDragImage(dragImage);
Point mousePosition = c.getMousePosition();
if (mousePosition != null) {
setDragImageOffset(mousePosition);
}
}
return COPY;
}
private final JPanel tempDrawPanel = new JPanel();
private BufferedImage createDragImage(JList<String> list) {
int width = 0;
int height = 0;
int[] selectedIndices = list.getSelectedIndices();
for(int i =0; i<selectedIndices.length; i++){
int idx = selectedIndices[i];
Rectangle cellBounds = list.getCellBounds(idx, idx);
height += cellBounds.height;
width = Math.max(width, cellBounds.width); // we want to create a drag image as big as the largest cell
}
BufferedImage br = null;
if (width > 0 && height > 0) {
br = list.getGraphicsConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
}
return br;
}
private BufferedImage makeImageFromString(JComponent src) {
JList<String> sourceList = (JList<String>)src;
BufferedImage br = createDragImage(sourceList);
if (br != null) {
int[] selectedIndices = sourceList.getSelectedIndices();
int yD = 0;
Graphics g = br.getGraphics();
try{
for(int idx: selectedIndices) {
ListCellRenderer<? super String> cellRenderer = sourceList.getCellRenderer();
String valueAt = sourceList.getModel().getElementAt(idx);
Component c = cellRenderer.getListCellRendererComponent(sourceList, valueAt, idx, false, false);
Rectangle itemCellBounds = sourceList.getCellBounds(idx, idx);
SwingUtilities.paintComponent(g, c, tempDrawPanel, itemCellBounds.x, yD, itemCellBounds.width, itemCellBounds.height);
yD = itemCellBounds.y+itemCellBounds.height;
}
}finally {
g.dispose();
}
br.coerceData(true);
}
return br;
}
#Override
protected Transferable createTransferable(JComponent c) {
JList<String> list = (JList<String>)c;
List<String> selectedValuesList = list.getSelectedValuesList();
StringBuffer buff = new StringBuffer();
for (int i = 0; i < selectedValuesList.size(); i++) {
String val = selectedValuesList.get(i);
buff.append(val == null ? "" : val.toString());
if (i != selectedValuesList.size()- 1) {
buff.append("\n");
}
}
return new StringSelection(buff.toString());
}
}
The problem lies, I think, somewhere in the makeImageFromString method, but after 2 days of digging through Swing/AWT libraries and understanding how the drag image is drawn, I still fail to fix this issue. The bottom-line question: is there any obscure logic in AWT that applies this gradient if the drag image is over a certain size?
Any help would be greatly appreciated!
Marius.
How about translates the origin of the graphics context:
//SwingUtilities.paintComponent(g, c, tempDrawPanel, itemCellBounds.x, yD, itemCellBounds.width, itemCellBounds.height);
//yD = itemCellBounds.y+itemCellBounds.height;
SwingUtilities.paintComponent(g, c, tempDrawPanel, 0, 0, itemCellBounds.width, itemCellBounds.height);
g.translate(0, itemCellBounds.height);
Edit:
#user3619696: I misunderstood.
I would guess that the "blurred drag image" opacity depend on the Windows desktop theme. So try using translucent JWindow instead of TransferHandler#setDragImage(...).
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.awt.image.*;
import java.util.List;
import javax.swing.*;
public class BasicTextListDND2 {
private JList<String> makeList() {
DefaultListModel<String> m = new DefaultListModel<String>();
for(int i = 0; i<10; i++) {
m.addElement("Element "+i);
}
JList<String> list = new JList<String>(m);
list.setTransferHandler(new BasicListTransferHandler());
list.setDropMode(DropMode.ON_OR_INSERT);
list.setDragEnabled(true);
list.setCellRenderer(new DefaultListCellRenderer() {
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 1L;
/** {#inheritDoc} */
public Component getListCellRendererComponent(JList<?> list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
Component listCellRendererComponent = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (cellHasFocus == false && isSelected == false) {
if (index % 2 == 0) {
listCellRendererComponent.setBackground(Color.RED);
} else if (index % 3==0) {
listCellRendererComponent.setBackground(Color.GREEN);
} else {
listCellRendererComponent.setBackground(Color.BLUE);
}
}
return listCellRendererComponent;
}
});
return list;
}
private JTextArea makeTextArea() {
JTextArea textArea = new JTextArea("Drag here from JList!");
return textArea;
}
public JComponent makeUI() {
JPanel panel = new JPanel(new GridLayout(2,1));
panel.add(new JScrollPane(makeTextArea()));
panel.add(new JScrollPane(makeList()));
return panel;
}
private static void createAndShowGUI() {
JFrame f = new JFrame("BasicDnD");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BasicTextListDND2 app = new BasicTextListDND2();
JComponent appContent = app.makeUI();
f.setContentPane(appContent);
f.setSize(600, 320);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
}
/**
*
*/
class BasicListTransferHandler extends TransferHandler {
/**
* Comment for <code>serialVersionUID</code>
*/
private static final long serialVersionUID = 1L;
private final JLabel label = new JLabel() {
#Override public boolean contains(int x, int y) {
return false;
}
};
private final JWindow window = new JWindow();
public BasicListTransferHandler() {
super();
window.add(label);
//window.setBackground(new Color(0, true));
window.setOpacity(.8f);
DragSource.getDefaultDragSource().addDragSourceMotionListener(new DragSourceMotionListener() {
#Override public void dragMouseMoved(DragSourceDragEvent dsde) {
Point pt = dsde.getLocation();
pt.translate(10, 10); // offset
if (!window.isVisible()) {
window.setVisible(true);
}
window.setLocation(pt);
}
});
}
#Override protected void exportDone(JComponent c, Transferable data, int action) {
super.exportDone(c, data, action);
window.setVisible(false);
}
#Override
public boolean canImport(TransferHandler.TransferSupport info) {
if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
JList.DropLocation dl = (JList.DropLocation)info.getDropLocation();
if (dl.getIndex() == -1) {
return false;
}
return true;
}
#Override
public int getSourceActions(JComponent c) {
BufferedImage dragImage = makeImageFromString(c);
if (dragImage != null) {
//setDragImage(dragImage);
//Point mousePosition = c.getMousePosition();
//if (mousePosition != null) {
// setDragImageOffset(mousePosition);
//}
label.setIcon(new ImageIcon(dragImage));
window.setLocation(-2000, -2000);
window.pack();
}
return COPY;
}
private final JPanel tempDrawPanel = new JPanel();
private BufferedImage createDragImage(JList<String> list) {
int width = 0;
int height = 0;
int[] selectedIndices = list.getSelectedIndices();
for(int i =0; i<selectedIndices.length; i++){
int idx = selectedIndices[i];
Rectangle cellBounds = list.getCellBounds(idx, idx);
height += cellBounds.height;
width = Math.max(width, cellBounds.width); // we want to create a drag image as big as the largest cell
}
BufferedImage br = null;
if (width > 0 && height > 0) {
br = list.getGraphicsConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
}
return br;
}
private BufferedImage makeImageFromString(JComponent src) {
JList<String> sourceList = (JList<String>)src;
BufferedImage br = createDragImage(sourceList);
if (br != null) {
int[] selectedIndices = sourceList.getSelectedIndices();
int yD = 0;
Graphics g = br.getGraphics();
try{
for(int idx: selectedIndices) {
ListCellRenderer<? super String> cellRenderer = sourceList.getCellRenderer();
String valueAt = sourceList.getModel().getElementAt(idx);
Component c = cellRenderer.getListCellRendererComponent(sourceList, valueAt, idx, false, false);
Rectangle itemCellBounds = sourceList.getCellBounds(idx, idx);
//SwingUtilities.paintComponent(g, c, tempDrawPanel, itemCellBounds.x, itemCellBounds.y + yD, itemCellBounds.width, itemCellBounds.height);
//yD = itemCellBounds.y+itemCellBounds.height;
SwingUtilities.paintComponent(g, c, tempDrawPanel, 0, 0, itemCellBounds.width, itemCellBounds.height);
g.translate(0, itemCellBounds.height);
}
}finally {
g.dispose();
}
br.coerceData(true);
}
return br;
}
#Override
protected Transferable createTransferable(JComponent c) {
JList<String> list = (JList<String>)c;
List<String> selectedValuesList = list.getSelectedValuesList();
StringBuffer buff = new StringBuffer();
for (int i = 0; i < selectedValuesList.size(); i++) {
String val = selectedValuesList.get(i);
buff.append(val == null ? "" : val.toString());
if (i != selectedValuesList.size()- 1) {
buff.append("\n");
}
}
return new StringSelection(buff.toString());
}
}

How to update jtable model correctly?

I have been thinking a lot to solve this mistake. But unfortunately I came to final cnclusion that I need help of professionals.
Please, copy,paste this code to see issue:
public class DateFormatDemo extends JFrame
{
private JTable dataSearchResultTable;
public DateFormatDemo()
{
JButton updateTable = new JButton("Update table");
updateTable.setMaximumSize(updateTable.getPreferredSize());
updateTable.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
updateMyTableModel();
}
});
JPanel panel = new JPanel(new GridLayout(2, 1, 5, 10));
panel.setPreferredSize(new Dimension(500, 300));
panel.add(new JScrollPane(initDataSearchResultTable()));
panel.add(updateTable);
super.getContentPane().add(panel);
super.pack();
super.setDefaultCloseOperation(EXIT_ON_CLOSE);
super.setVisible(true);
}
private JTable initDataSearchResultTable()
{
dataSearchResultTable = new JTable();
// dataSearchResultTable.setAutoCreateColumnsFromModel(false);
dataSearchResultTable.setSelectionBackground(new Color(0xaaaaff));
dataSearchResultTable.setFillsViewportHeight(true);
dataSearchResultTable.setRowSelectionAllowed(true);
dataSearchResultTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
dataSearchResultTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
return dataSearchResultTable;
}
void updateMyTableModel()
{
TableModel tableModel = dataSearchResultTable.getModel();
TableColumnModel columnModel = dataSearchResultTable.getColumnModel();
if (tableModel instanceof MyTableModel) {
((MyTableModel) tableModel).updateModel();
this.initColumnWidths(tableModel, columnModel);
} else {
tableModel = new MyTableModel();
dataSearchResultTable.setModel(tableModel);
this.makeColumnsNotResizable(columnModel);
this.initColumnWidths(tableModel, columnModel);
}
}
private void makeColumnsNotResizable(TableColumnModel columnModel)
{
for (int i = 0; i < columnModel.getColumnCount(); i++) {
if (i == 0 || i == 1) {
columnModel.getColumn(i).setResizable(false);
}
}
}
private void initColumnWidths(TableModel tableModel, TableColumnModel columnModel)
{
TableColumn column = null;
Component comp = null;
int cellWidth = 0;
int headerWidth = 0;
TableCellRenderer headerRenderer = dataSearchResultTable.getTableHeader().getDefaultRenderer();
for (int i = 0; i < columnModel.getColumnCount(); i++) {
column = columnModel.getColumn(i);
comp = headerRenderer.getTableCellRendererComponent(null, column.getHeaderValue(), false, false, -1, 0);
headerWidth = comp.getPreferredSize().width;
Class<?> columnClass = tableModel.getColumnClass(i);
for (int j = 0; j < tableModel.getRowCount(); j++) {
comp = dataSearchResultTable.getDefaultRenderer(columnClass).getTableCellRendererComponent(
dataSearchResultTable, tableModel.getValueAt(j, i), false, false, j, i);
int width = comp.getPreferredSize().width;
// we cache width of first row. And compare widths of next
// rows with width of first.
// If some row has greater width it becomes width of whole
// row(unless header has greater width)
if (cellWidth < width || j == 0) {
cellWidth = width;
}
}
System.out
.println("columnClass=" + columnClass + ",headerWidth=" + headerWidth + ",cellWidth=" + cellWidth);
if (headerWidth > cellWidth) {
TableCellRenderer centeredRenderer = dataSearchResultTable.getDefaultRenderer(columnClass);
if (centeredRenderer instanceof DefaultTableCellRenderer) {
((DefaultTableCellRenderer) centeredRenderer).setHorizontalAlignment(SwingConstants.CENTER);
column.setCellRenderer(centeredRenderer);
column.setPreferredWidth(headerWidth);
}
} else {
column.setPreferredWidth(cellWidth + 5);
}
}
}
class MyTableModel extends AbstractTableModel
{
private String[] columnNames = { "First Name", "Last Name", "Timestamp", "Number", "Vegetarian" };
private Object[][] data = new Object[5][];
void updateModel()
{
data = new Object[][] {
{ "Vova", "KipokKipokKipokKipok", "2013-04-12 11:20:41", new Integer(5), new Boolean(true) },
{ "Olia", "Duo", "2010-01-11 11:11:41", new Integer(3), new Boolean(false) },
{ "Oksana", "Stack", "2012-04-12 11:20:41", new Integer(2), new Boolean(false) },
{ "Petro", "White", "2010-04-12 11:20:21", new Integer(20), new Boolean(true) },
{ "Ivan", "Brown", "2011-04-11 11:20:41", new Integer(10), new Boolean(true) } };
fireTableDataChanged();
}
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)
{
if (data.length > 0 && data[0] != null) {
return data[row][col];
}
return null;
}
/*
* JTable uses this method to determine the default renderer/ editor for
* each cell. If we didn't implement this method, then the last column
* would contain text ("true"/"false"), rather than a check box.
*/
public Class getColumnClass(int c)
{
Object valueAt = getValueAt(0, c);
return valueAt == null ? Object.class : valueAt.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)
{
if (data.length > 0 && data[0] != null) {
data[row][col] = value;
fireTableCellUpdated(row, col);
}
}
}
public static void main(String[] args) throws ParseException
{
new DateFormatDemo();
}
}
Now please click twice on that big button called 'Update Table'. As you see column that should display checkbox as it holds boolean values do not do that but instead displays String true or false.
This code emulates my real workflow.
So, how to update tablemodel to have boolean columns with checkbozes.
Thanks!
take this as simple start point
import java.awt.*;
import java.util.Random;
import java.util.Vector;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
public class Forum implements ListSelectionListener {
private JFrame frame = new JFrame("Frame");
private JPanel fatherCenter = new JPanel();
private JScrollPane tableScroll = new JScrollPane();
private MyTableModel tableModel;
private JTable dialogTable;
private ListSelectionModel lsDialog;
private Color clr;
private Color clr1;
private void addData() {
Runnable doRun1 = new Runnable() {
#Override
public void run() {
tableModel.resetTable();
Vector<String> tbl = new Vector<String>();
Vector<Object> tbl1 = new Vector<Object>();
Random rnd = new Random();
tbl.add("Integer");
tbl.add("Double");
tbl.add("Boolean");
tbl.add("Boolean");
tbl.add("String");
tableModel.setColumnNames(tbl);
for (int row = 0; row < 30; row++) {
tbl1 = null;
tbl1 = new Vector<Object>();
tbl1.addElement(row + 1);
tbl1.addElement(rnd.nextInt(25) + 3.14);
tbl1.addElement((row % 3 == 0) ? false : true);
tbl1.addElement((row % 5 == 0) ? false : true);
if (row % 7 == 0) {
tbl1.add(("Canc"));
} else if (row % 6 == 0) {
tbl1.add(("Del"));
} else {
tbl1.add(("New"));
}
tableModel.addRow(tbl1);
}
addTableListener();
}
};
SwingUtilities.invokeLater(doRun1);
}
private void addTableListener() {
tableModel.addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent tme) {
if (tme.getType() == TableModelEvent.UPDATE) {
System.out.println("");
System.out.println("Cell " + tme.getFirstRow() + ", "
+ tme.getColumn() + " changed. The new value: "
+ tableModel.getValueAt(tme.getFirstRow(),
tme.getColumn()));
}
}
});
}
#Override
public void valueChanged(ListSelectionEvent le) {
int row = dialogTable.getSelectedRow();
int col = dialogTable.getSelectedColumn();
String str = "Selected Row(s): ";
int[] rows = dialogTable.getSelectedRows();
for (int i = 0; i < rows.length; i++) {
str += rows[i] + " ";
}
str += "Selected Column(s): ";
int[] cols = dialogTable.getSelectedColumns();
for (int i = 0; i < cols.length; i++) {
str += cols[i] + " ";
}
str += "Selected Cell: " + dialogTable.getSelectedRow() + ", " + dialogTable.getSelectedColumn();
System.out.println(str);
Object value = dialogTable.getValueAt(row, col);
System.out.println(String.valueOf(value));
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Forum osFrame = new Forum();
}
});
}
public Forum() {
tableModel = new MyTableModel();
dialogTable = new JTable(tableModel) {
private static final long serialVersionUID = 1L;
#Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component comp = super.prepareRenderer(renderer, row, column);
JComponent jc = (JComponent) comp;//for Custom JComponent
if (!isRowSelected(row)) {
int modelRow = convertRowIndexToModel(row);
boolean type = (Boolean) getModel().getValueAt(modelRow, 2);
boolean type1 = (Boolean) getModel().getValueAt(modelRow, 3);
comp.setForeground(Color.black);
if ((type) && (!type1)) {
comp.setBackground(clr1);
} else if ((!type) && (type1)) {
comp.setBackground(Color.orange);
} else if ((!type) || (!type1)) {
comp.setBackground(Color.red);
} else {
comp.setBackground(row % 2 == 0 ? getBackground() : getBackground().darker());
}
dialogTable.convertRowIndexToView(0);
} else {
comp.setForeground(Color.blue);
}
if (!isCellEditable(row, column)) {
comp.setForeground(Color.red);
comp.setBackground(Color.magenta);
}
return comp;
}
};
tableScroll = new JScrollPane(dialogTable, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
tableScroll.setBorder(null);
dialogTable.getTableHeader().setReorderingAllowed(false);
dialogTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
lsDialog = dialogTable.getSelectionModel();
dialogTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
dialogTable.setRowHeight(20);
dialogTable.setRowMargin(2);
dialogTable.setPreferredScrollableViewportSize(dialogTable.getPreferredSize());
ListSelectionModel rowSelMod = dialogTable.getSelectionModel();
//ListSelectionModel colSelMod = dialogTable.getColumnModel().getSelectionModel();
rowSelMod.addListSelectionListener(this);
//colSelMod.addListSelectionListener(this);
fatherCenter = new JPanel();
fatherCenter.setLayout(new BorderLayout(10, 10));
fatherCenter.add(tableScroll, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout(10, 10));
frame.add(fatherCenter);
frame.setPreferredSize(new Dimension(400, 660));
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
addData();
}
private class MyTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
private Vector<Vector<Object>> _data;
private Vector<String> _colNames;
private boolean[] _columnsVisible = {true, true, true, true, true};
public MyTableModel() {
_colNames = new Vector<String>();
_data = new Vector<Vector<Object>>();
}
public MyTableModel(Vector<String> colnames) {
_colNames = colnames;
_data = new Vector<Vector<Object>>();
}
public void resetTable() {
_colNames.removeAllElements();
_data.removeAllElements();
}
public void setColumnNames(Vector<String> colNames) {
_colNames = colNames;
fireTableStructureChanged();
}
public void addRow(Vector<Object> data) {
_data.add(data);
fireTableRowsInserted(_data.size() - 1, _data.size() - 1);
}
public void removeRowAt(int row) {
_data.removeElementAt(row);
fireTableRowsDeleted(row - 1, _data.size() - 1);
}
#Override
public int getColumnCount() {
return _colNames.size();
}
#Override
public Class<?> getColumnClass(int colNum) {
switch (colNum) {
case 0:
return Integer.class;
case 1:
return Double.class;
case 2:
return Boolean.class;
case 3:
return Boolean.class;
default:
return String.class;
}
}
#Override
public boolean isCellEditable(int row, int colNum) {
switch (colNum) {
case 2:
return false;
default:
return true;
}
}
#Override
public String getColumnName(int colNum) {
return _colNames.get(colNum);
}
#Override
public int getRowCount() {
return _data.size();
}
#Override
public Object getValueAt(int row, int col) {
Vector<Object> value = _data.get(row);
return value.get(col);
}
#Override
public void setValueAt(Object newVal, int row, int col) {
Vector<Object> aRow = _data.elementAt(row);
aRow.remove(col);
aRow.insertElementAt(newVal, col);
fireTableCellUpdated(row, col);
}
public void setColumnVisible(int index, boolean visible) {
_columnsVisible[index] = visible;
fireTableStructureChanged();
}
}
}
Your problem in getColumnClass method as you see you also return Object because of that you also get String columns.
You can determine that method in next way:
#Override
public Class<?> getColumnClass(int arg0) {
return longValues[arg0].getClass();
}
Or return Classes for your columns in another way. But you must to determine this Classes while cunstruct your model.

Minesweeper Action Events

Is there a way to make certain event actions specific to left and right mouse clicks?
I'm creating a minesweeper gui, so when a square is left-clicked it will be uncovered, & when it's right-clicked it will be flagged.
I wasn't sure how to syntactically check for this & couldn't find it on the tut.
Thanks for the help!
I decided to give it a go, to try to create a simple Mine Sweeper application, one without a timer or reset (yet), but that is functional and uses both a GUI cell class and a non-GUI model class (it can't be copied and used in for intro to Java homework).
Edit 1: now has reset capability:
MineSweeper.java: holds the main method and starts the JFrame
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class MineSweeper {
private JPanel mainPanel = new JPanel();
private MineCellGrid mineCellGrid;
private JButton resetButton = new JButton("Reset");
public MineSweeper(int rows, int cols, int mineTotal) {
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
mineCellGrid = new MineCellGrid(rows, cols, mineTotal);
resetButton.setMnemonic(KeyEvent.VK_R);
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
mineCellGrid.reset();
}
});
mainPanel.add(mineCellGrid);
mainPanel.add(new JSeparator());
mainPanel.add(new JPanel(){{add(resetButton);}});
}
private JPanel getMainPanel() {
return mainPanel;
}
private static void createAndShowUI() {
JFrame frame = new JFrame("MineSweeper");
//frame.getContentPane().add(new MineSweeper(20, 20, 44).getMainPanel());
frame.getContentPane().add(new MineSweeper(12, 12, 13).getMainPanel());
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();
}
});
}
}
MineCellGrid.java: the class that displays the grid of mine cells and times them all together.
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class MineCellGrid extends JPanel {
private MineCellGridModel model;
private List<MineCell> mineCells = new ArrayList<MineCell>();
public MineCellGrid(final int maxRows, final int maxCols, int mineNumber) {
model = new MineCellGridModel(maxRows, maxCols, mineNumber);
setLayout(new GridLayout(maxRows, maxCols));
for (int row = 0; row < maxRows; row++) {
for (int col = 0; col < maxCols; col++) {
MineCell mineCell = new MineCell(row, col);
add(mineCell);
mineCells.add(mineCell);
model.add(mineCell.getModel(), row, col);
}
}
reset();
}
public void reset() {
model.reset();
for (MineCell mineCell : mineCells) {
mineCell.reset();
}
}
}
MineCellGridModel.java: the non-GUI model for the MineCellGrid
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JOptionPane;
public class MineCellGridModel {
private MineCellModel[][] cellModelGrid;
private List<Boolean> mineList = new ArrayList<Boolean>();
private CellModelPropertyChangeListener cellModelPropChangeListener = new CellModelPropertyChangeListener();
private int maxRows;
private int maxCols;
private int mineNumber;
private int buttonsRemaining;
public MineCellGridModel(final int maxRows, final int maxCols, int mineNumber) {
this.maxRows = maxRows;
this.maxCols = maxCols;
this.mineNumber = mineNumber;
for (int i = 0; i < maxRows * maxCols; i++) {
mineList.add((i < mineNumber) ? true : false);
}
cellModelGrid = new MineCellModel[maxRows][maxCols];
buttonsRemaining = (maxRows * maxCols) - mineNumber;
}
public void add(MineCellModel model, int row, int col) {
cellModelGrid[row][col] = model;
model.addPropertyChangeListener(cellModelPropChangeListener);
}
public void reset() {
buttonsRemaining = (maxRows * maxCols) - mineNumber;
// randomize the mine location
Collections.shuffle(mineList);
// reset the model grid and set mines
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
cellModelGrid[r][c].reset();
cellModelGrid[r][c].setMined(mineList.get(r
* cellModelGrid[r].length + c));
}
}
// advance value property of all neighbors of a mined cell
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
if (cellModelGrid[r][c].isMined()) {
int rMin = Math.max(r - 1, 0);
int cMin = Math.max(c - 1, 0);
int rMax = Math.min(r + 1, cellModelGrid.length - 1);
int cMax = Math.min(c + 1, cellModelGrid[r].length - 1);
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
cellModelGrid[row2][col2].incrementValue();
}
}
}
}
}
}
private class CellModelPropertyChangeListener implements
PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
MineCellModel model = (MineCellModel) evt.getSource();
int row = model.getRow();
int col = model.getCol();
if (evt.getPropertyName().equals(MineCellModel.BUTTON_PRESSED)) {
if (cellModelGrid[row][col].isMineBlown()) {
mineBlown();
} else {
buttonsRemaining--;
if (buttonsRemaining <= 0) {
JOptionPane.showMessageDialog(null, "You've Won!!!", "Congratulations", JOptionPane.PLAIN_MESSAGE);
}
if (cellModelGrid[row][col].getValue() == 0) {
zeroValuePress(row, col);
}
}
}
}
private void mineBlown() {
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
MineCellModel model = cellModelGrid[r][c];
if (model.isMined()) {
model.setMineBlown(true);
}
}
}
}
private void zeroValuePress(int row, int col) {
int rMin = Math.max(row - 1, 0);
int cMin = Math.max(col - 1, 0);
int rMax = Math.min(row + 1, cellModelGrid.length - 1);
int cMax = Math.min(col + 1, cellModelGrid[row].length - 1);
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
cellModelGrid[row2][col2].pressedAction();
}
}
}
}
}
MineCell.java: the class that I started on. Uses the model class as its non-GUI nucleus.
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
/**
* http://stackoverflow.com/questions/7006029/minesweeper-action-events
*
* #author Pete
*/
#SuppressWarnings("serial")
public class MineCell extends JPanel {
private static final String LABEL = "label";
private static final String BUTTON = "button";
private static final int PS_WIDTH = 24;
private static final int PS_HEIGHT = PS_WIDTH;
private static final float LABEL_FONT_SIZE = (float) (24 * PS_WIDTH) / 30f;
private static final float BUTTON_FONT_SIZE = (float) (14 * PS_WIDTH) / 30f;
private JButton button = new JButton();
private JLabel label = new JLabel(" ", SwingConstants.CENTER);
private CardLayout cardLayout = new CardLayout();
private MineCellModel model;
public MineCell(final boolean mined, int row, int col) {
model = new MineCellModel(mined, row, col);
model.addPropertyChangeListener(new MyPCListener());
label.setFont(label.getFont().deriveFont(Font.BOLD, LABEL_FONT_SIZE));
button.setFont(button.getFont().deriveFont(Font.PLAIN, BUTTON_FONT_SIZE));
button.setMargin(new Insets(1, 1, 1, 1));
setLayout(cardLayout);
add(button, BUTTON);
add(label, LABEL);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
pressedAction();
}
});
button.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
model.upDateButtonFlag();
}
}
});
}
public MineCell(int row, int col) {
this(false, row, col);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PS_WIDTH, PS_HEIGHT);
}
public void pressedAction() {
if (model.isFlagged()) {
return;
}
model.pressedAction();
}
public void showCard(String cardConstant) {
cardLayout.show(this, cardConstant);
}
// TODO: have this change the button's icon
public void setFlag(boolean flag) {
if (flag) {
button.setBackground(Color.yellow);
button.setForeground(Color.red);
button.setText("f");
} else {
button.setBackground(null);
button.setForeground(null);
button.setText("");
}
}
private void setMineBlown(boolean mineBlown) {
if (mineBlown) {
label.setBackground(Color.red);
label.setOpaque(true);
showCard(LABEL);
} else {
label.setBackground(null);
}
}
public MineCellModel getModel() {
return model;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
model.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
model.removePropertyChangeListener(listener);
}
private class MyPCListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
String propName = evt.getPropertyName();
if (propName.equals(MineCellModel.MINE_BLOWN)) {
setMineBlown(true);
} else if (propName.equals(MineCellModel.FLAG_CHANGE)) {
setFlag(model.isFlagged());
} else if (propName.equals(MineCellModel.BUTTON_PRESSED)) {
if (model.isMineBlown()) {
setMineBlown(true);
} else {
String labelText = (model.getValue() == 0) ? "" : String
.valueOf(model.getValue());
label.setText(labelText);
}
showCard(LABEL);
}
}
}
public void reset() {
setFlag(false);
setMineBlown(false);
showCard(BUTTON);
label.setText("");
}
}
MineCellModel.java: the non-GUI model for the mine cell
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.event.SwingPropertyChangeSupport;
class MineCellModel {
public static final String FLAG_CHANGE = "Flag Change";
public static final String BUTTON_PRESSED = "Button Pressed";
public static final String MINE_BLOWN = "Mine Blown";
private int row;
private int col;
private int value = 0;
private boolean mined = false;;
private boolean flagged = false;
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
this);
private boolean pressed = false;
private boolean mineBlown = false;
public MineCellModel(boolean mined, int row, int col) {
this.mined = mined;
this.row = row;
this.col = col;
}
public void incrementValue() {
int temp = value + 1;
setValue(temp);
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setMineBlown(boolean mineBlown) {
this.mineBlown = mineBlown;
PropertyChangeEvent evt = new PropertyChangeEvent(this, MINE_BLOWN, false, true);
pcSupport.firePropertyChange(evt);
}
public boolean isMineBlown() {
return mineBlown;
}
public void setMined(boolean mined) {
this.mined = mined;
}
public void setFlagged(boolean flagged) {
this.flagged = flagged;
}
public int getRow() {
return row;
}
public int getCol() {
return col;
}
public boolean isMined() {
return mined;
}
public boolean isFlagged() {
return flagged;
}
public void pressedAction() {
if (pressed) {
return;
}
pressed = true;
if (mined) {
setMineBlown(true);
}
PropertyChangeEvent evt = new PropertyChangeEvent(this, BUTTON_PRESSED,
-1, value);
pcSupport.firePropertyChange(evt);
}
public void upDateButtonFlag() {
boolean oldValue = flagged;
setFlagged(!flagged);
PropertyChangeEvent evt = new PropertyChangeEvent(this, FLAG_CHANGE,
oldValue, flagged);
pcSupport.firePropertyChange(evt);
}
public void reset() {
mined = false;
flagged = false;
pressed = false;
mineBlown = false;
value = 0;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
}
Here's the whole program combined into a single MCVE file, MineSweeper.java:
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.*;
import java.beans.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.*;
import javax.swing.event.*;
#SuppressWarnings("serial")
public class MineSweeper {
private JPanel mainPanel = new JPanel();
private MineCellGrid mineCellGrid;
private JButton resetButton = new JButton("Reset");
public MineSweeper(int rows, int cols, int mineTotal) {
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
mineCellGrid = new MineCellGrid(rows, cols, mineTotal);
resetButton.setMnemonic(KeyEvent.VK_R);
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
mineCellGrid.reset();
}
});
mainPanel.add(mineCellGrid);
mainPanel.add(new JSeparator());
mainPanel.add(new JPanel() {
{
add(resetButton);
}
});
}
private JPanel getMainPanel() {
return mainPanel;
}
private static void createAndShowUI() {
JFrame frame = new JFrame("MineSweeper");
// frame.getContentPane().add(new MineSweeper(20, 20,
// 44).getMainPanel());
frame.getContentPane().add(new MineSweeper(12, 12, 13).getMainPanel());
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();
}
});
}
}
#SuppressWarnings("serial")
class MineCellGrid extends JPanel {
private MineCellGridModel model;
private List<MineCell> mineCells = new ArrayList<>();
public MineCellGrid(final int maxRows, final int maxCols, int mineNumber) {
model = new MineCellGridModel(maxRows, maxCols, mineNumber);
setLayout(new GridLayout(maxRows, maxCols));
for (int row = 0; row < maxRows; row++) {
for (int col = 0; col < maxCols; col++) {
MineCell mineCell = new MineCell(row, col);
add(mineCell);
mineCells.add(mineCell);
model.add(mineCell.getModel(), row, col);
}
}
reset();
}
public void reset() {
model.reset();
for (MineCell mineCell : mineCells) {
mineCell.reset();
}
}
}
class MineCellGridModel {
private MineCellModel[][] cellModelGrid;
private List<Boolean> mineList = new ArrayList<Boolean>();
private CellModelPropertyChangeListener cellModelPropChangeListener = new CellModelPropertyChangeListener();
private int maxRows;
private int maxCols;
private int mineNumber;
private int buttonsRemaining;
public MineCellGridModel(final int maxRows, final int maxCols, int mineNumber) {
this.maxRows = maxRows;
this.maxCols = maxCols;
this.mineNumber = mineNumber;
for (int i = 0; i < maxRows * maxCols; i++) {
mineList.add((i < mineNumber) ? true : false);
}
cellModelGrid = new MineCellModel[maxRows][maxCols];
buttonsRemaining = (maxRows * maxCols) - mineNumber;
}
public void add(MineCellModel model, int row, int col) {
cellModelGrid[row][col] = model;
model.addPropertyChangeListener(cellModelPropChangeListener);
}
public void reset() {
buttonsRemaining = (maxRows * maxCols) - mineNumber;
// randomize the mine location
Collections.shuffle(mineList);
// reset the model grid and set mines
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
cellModelGrid[r][c].reset();
cellModelGrid[r][c].setMined(mineList.get(r * cellModelGrid[r].length + c));
}
}
// advance value property of all neighbors of a mined cell
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
if (cellModelGrid[r][c].isMined()) {
int rMin = Math.max(r - 1, 0);
int cMin = Math.max(c - 1, 0);
int rMax = Math.min(r + 1, cellModelGrid.length - 1);
int cMax = Math.min(c + 1, cellModelGrid[r].length - 1);
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
cellModelGrid[row2][col2].incrementValue();
}
}
}
}
}
}
private class CellModelPropertyChangeListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
MineCellModel model = (MineCellModel) evt.getSource();
int row = model.getRow();
int col = model.getCol();
if (evt.getPropertyName().equals(MineCellModel.BUTTON_PRESSED)) {
if (cellModelGrid[row][col].isMineBlown()) {
mineBlown();
} else {
buttonsRemaining--;
if (buttonsRemaining <= 0) {
JOptionPane.showMessageDialog(null, "You've Won!!!", "Congratulations",
JOptionPane.PLAIN_MESSAGE);
}
if (cellModelGrid[row][col].getValue() == 0) {
zeroValuePress(row, col);
}
}
}
}
private void mineBlown() {
for (int r = 0; r < cellModelGrid.length; r++) {
for (int c = 0; c < cellModelGrid[r].length; c++) {
MineCellModel model = cellModelGrid[r][c];
if (model.isMined()) {
model.setMineBlown(true);
}
}
}
}
private void zeroValuePress(int row, int col) {
int rMin = Math.max(row - 1, 0);
int cMin = Math.max(col - 1, 0);
int rMax = Math.min(row + 1, cellModelGrid.length - 1);
int cMax = Math.min(col + 1, cellModelGrid[row].length - 1);
for (int row2 = rMin; row2 <= rMax; row2++) {
for (int col2 = cMin; col2 <= cMax; col2++) {
cellModelGrid[row2][col2].pressedAction();
}
}
}
}
}
#SuppressWarnings("serial")
class MineCell extends JPanel {
private static final String LABEL = "label";
private static final String BUTTON = "button";
private static final int PS_WIDTH = 24;
private static final int PS_HEIGHT = PS_WIDTH;
private static final float LABEL_FONT_SIZE = (float) (24 * PS_WIDTH) / 30f;
private static final float BUTTON_FONT_SIZE = (float) (14 * PS_WIDTH) / 30f;
private JButton button = new JButton();
private JLabel label = new JLabel(" ", SwingConstants.CENTER);
private CardLayout cardLayout = new CardLayout();
private MineCellModel model;
public MineCell(final boolean mined, int row, int col) {
model = new MineCellModel(mined, row, col);
model.addPropertyChangeListener(new MyPCListener());
label.setFont(label.getFont().deriveFont(Font.BOLD, LABEL_FONT_SIZE));
button.setFont(button.getFont().deriveFont(Font.PLAIN, BUTTON_FONT_SIZE));
button.setMargin(new Insets(1, 1, 1, 1));
setLayout(cardLayout);
add(button, BUTTON);
add(label, LABEL);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
pressedAction();
}
});
button.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
model.upDateButtonFlag();
}
}
});
}
public MineCell(int row, int col) {
this(false, row, col);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PS_WIDTH, PS_HEIGHT);
}
public void pressedAction() {
if (model.isFlagged()) {
return;
}
model.pressedAction();
}
public void showCard(String cardConstant) {
cardLayout.show(this, cardConstant);
}
// TODO: have this change the button's icon
public void setFlag(boolean flag) {
if (flag) {
button.setBackground(Color.yellow);
button.setForeground(Color.red);
button.setText("f");
} else {
button.setBackground(null);
button.setForeground(null);
button.setText("");
}
}
private void setMineBlown(boolean mineBlown) {
if (mineBlown) {
label.setBackground(Color.red);
label.setOpaque(true);
showCard(LABEL);
} else {
label.setBackground(null);
}
}
public MineCellModel getModel() {
return model;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
model.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
model.removePropertyChangeListener(listener);
}
private class MyPCListener implements PropertyChangeListener {
public void propertyChange(PropertyChangeEvent evt) {
String propName = evt.getPropertyName();
if (propName.equals(MineCellModel.MINE_BLOWN)) {
setMineBlown(true);
} else if (propName.equals(MineCellModel.FLAG_CHANGE)) {
setFlag(model.isFlagged());
} else if (propName.equals(MineCellModel.BUTTON_PRESSED)) {
if (model.isMineBlown()) {
setMineBlown(true);
} else {
String labelText = (model.getValue() == 0) ? ""
: String.valueOf(model.getValue());
label.setText(labelText);
}
showCard(LABEL);
}
}
}
public void reset() {
setFlag(false);
setMineBlown(false);
showCard(BUTTON);
label.setText("");
}
}
class MineCellModel {
public static final String FLAG_CHANGE = "Flag Change";
public static final String BUTTON_PRESSED = "Button Pressed";
public static final String MINE_BLOWN = "Mine Blown";
private int row;
private int col;
private int value = 0;
private boolean mined = false;;
private boolean flagged = false;
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
private boolean pressed = false;
private boolean mineBlown = false;
public MineCellModel(boolean mined, int row, int col) {
this.mined = mined;
this.row = row;
this.col = col;
}
public void incrementValue() {
int temp = value + 1;
setValue(temp);
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setMineBlown(boolean mineBlown) {
this.mineBlown = mineBlown;
PropertyChangeEvent evt = new PropertyChangeEvent(this, MINE_BLOWN, false, true);
pcSupport.firePropertyChange(evt);
}
public boolean isMineBlown() {
return mineBlown;
}
public void setMined(boolean mined) {
this.mined = mined;
}
public void setFlagged(boolean flagged) {
this.flagged = flagged;
}
public int getRow() {
return row;
}
public int getCol() {
return col;
}
public boolean isMined() {
return mined;
}
public boolean isFlagged() {
return flagged;
}
public void pressedAction() {
if (pressed) {
return;
}
pressed = true;
if (mined) {
setMineBlown(true);
}
PropertyChangeEvent evt = new PropertyChangeEvent(this, BUTTON_PRESSED, -1, value);
pcSupport.firePropertyChange(evt);
}
public void upDateButtonFlag() {
boolean oldValue = flagged;
setFlagged(!flagged);
PropertyChangeEvent evt = new PropertyChangeEvent(this, FLAG_CHANGE, oldValue, flagged);
pcSupport.firePropertyChange(evt);
}
public void reset() {
mined = false;
flagged = false;
pressed = false;
mineBlown = false;
value = 0;
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
}
If you are using swing then
Is there a way to make certain event actions specific to left and
right mouse clicks?
Implement a MouseListener no component. Then in implemented method you have a MouseEvent object which has a getButton() method which tells you which mouse is pressed.
Edit
OP has asked following question but now removed it.
Is this gui nested inside the other in an action event, when
game_lost becomes true?
You can open a JDialog for this.
You may be interested in the MouseEvent Class of java.awt.event. here

Categories