Editing JTable cells after being cloned - java

I'm working on a project for work and I have reached an unusual problem. I have a JTable that the user can populate with data. In my actual code there is an "add row" button that lets the user fill out some GUI's and that information generates the row.
Another important feature of this is a button to clone rows. Since the process of adding a row can be very time consuming (there are many fields to fill out) if a user only needs to add a new row with 1 cell different then he can clone the cell using the button.
This clone button works as expected however there is a rather odd problem. Once a row has been cloned I noticed that when I attempt to change the contents of any cells that have been cloned there are unexpected results. For example if I change a cell's contents to "Ryan" then other cells may also suddenly change and if I even click on a cell after changing one the cell I click on will change by itself. I'm quite sure that this problem is related to the clone method I just really have no idea to fix.
I created a verifiable program so you can text it out for yourself and see what I'm talking about. Just use the clone button a few times and then try changing the contents of individual cells and watch the results in the other cells..
I really need to fix this but I'm lost on what to do, and help is GREATLY appreciated.
Main Class
package jtabletest;
public class JTableTestMain
{
public static void main(String args[]){
JTableTest jTest = new JTableTest();
jTest.createGUI();
}
}
JTable Class
package jtabletest;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
public class JTableTest
{
protected static DefaultTableModel dtm = new DefaultTableModel();
public static JTable tbl;
public void createGUI(){
final JFrame frame = new JFrame("JTable Test");
JPanel mainPanel = new JPanel(new BorderLayout());
JPanel panelNorth = new JPanel(new BorderLayout());
JPanel panelSouth = new JPanel(new BorderLayout());
JPanel buttonPanel = new JPanel();
JButton cloneButton = new JButton("Clone");
cloneButton.setPreferredSize(new Dimension(150,40));
buttonPanel.add(cloneButton);
JButton printButton = new JButton("Print");
printButton.setPreferredSize(new Dimension(150,40));
buttonPanel.add(printButton);
tbl = new JTable();
String header[] = new String[]{
"Employee", "Pay-Rate", "Hours Worked"};
dtm.setColumnIdentifiers(header);
tbl.setModel(dtm);
tbl.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
for(int i = 0; i < header.length; i++){
tbl.getColumnModel().getColumn(i).setPreferredWidth(200);
}
dtm.addRow(new Object[]{"Pete","$10.00","40"});
dtm.addRow(new Object[]{"Bob","12.50","42"});
dtm.addRow(new Object[]{"Jamar","$7.25,25"});
cloneButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
int[] selectedRows = tbl.getSelectedRows();
if(selectedRows.length>0){
#SuppressWarnings("rawtypes")
Vector data = dtm.getDataVector();
int insertPoint = selectedRows[selectedRows.length-1]+1;
for(int i = 0; i < selectedRows.length; i++){
#SuppressWarnings("rawtypes")
Vector targetRow = (Vector)data.elementAt(selectedRows[i]);
dtm.insertRow(insertPoint, targetRow);
insertPoint++;
}
dtm.fireTableDataChanged();
}
}
});
printButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
if(null != tbl.getCellEditor()){
tbl.getCellEditor().stopCellEditing();
}
for(int i = 0; i < tbl.getRowCount(); i++){
System.out.println(tbl.getValueAt(i, 0));
System.out.println(tbl.getValueAt(i, 1));
System.out.println(tbl.getValueAt(i, 2));
}
}
});
panelNorth.add(tbl,BorderLayout.NORTH);
panelNorth.setPreferredSize(new Dimension(500,500));
panelSouth.add(buttonPanel,BorderLayout.NORTH);
mainPanel.add(panelNorth,BorderLayout.NORTH);
mainPanel.add(panelSouth,BorderLayout.SOUTH);
frame.add(mainPanel);
frame.setVisible(true);
frame.setSize(1900,600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

It sounds like you are reusing the same reference rather than copying new objects on the clone method. I would suggest doing the following.
1) First create a new Vector and see if that will do the trick, like so.
for(int i = 0; i < selectedRows.length; i++){
#SuppressWarnings("rawtypes")
Vector targetRow = (Vector)data.elementAt(selectedRows[i]);
Vector newVector = new Vector();
for (int t = 0; t < targetRow.size(); t++) {
newVector.add(targetRow.get(t));
}
dtm.insertRow(insertPoint, newVector);
insertPoint++;
}
and see if this will resolve your problem. If it does you are done. If it doesn't then
2) Create a new Vector similar to above, for any Class based object in the Vector recreate them as currently you are dealing with pointers.
It's a bit hard for me to say if #1 will fix your problem as I don't know the contents of the Vector coming from the table, if it is primitives you are probably safe otherwise you may need to do solution #2.

Your problem is in this line:
Vector targetRow = (Vector)data.elementAt(selectedRows[i]);
you are not creating a copy, you are creating a new reference so when you add
dtm.insertRow(insertPoint, targetRow)
the row you are adding is actually the same, not a copy of the previosly selected row.
You will have to use something like
Vector aux = (Vector)data.elementAt(selectedRows[i]);
Vector targetRow = aux.clone();
to make it work.

Clone is the keyword here. You are not cloning the data. You are just copying the references from one Vector to another. So since each row shares the same references the value appears in both rows.
So you need to actually clone each element.
The code would be something like:
Vector targetRow = (Vector)data.elementAt(selectedRows[i]);
Vector clonedRow = new Vector(targetRow.size());
for (Object object: targetRow)
{
clonedRow.addElement( object.clone() );
}
Note, I've never used clone() before so you might be able to use:
Vector targetRow = (Vector)data.elementAt(selectedRows[i]);
Vector clonedRow = targetRow.clone();
but I'm not sure if it just clones the Vector and not the elements in the Vector.
Also, you would never invoke the firstTableDataChanged() method. That is the job of the DefaultTableModle to fire the appropriate method when the insertRow(...) method is invoked.
Edit:
Yes, using the clone does work but you need to clone the Vector not each item in the Vector:
//dtm.insertRow(insertPoint, targetRow);
dtm.insertRow(insertPoint, (Vector)targetRow.clone());
or
dtm.insertRow(insertPoint, new Vector(targetRow));

Related

Making an interactive GUI in Java for own program

To start with -- I'm not sure, that I have properly formulated the question (I'm new in Java and in making programs with GUI).
It is the following thing, I'm trying to do. I have a window with several similar parameters (numbers are just for distinction between lines and it ist just very simplified example, of what should my GUI be):
Initial Window
Then, by clicking on the "+"-button I would like to add an new line, like here:
Line 35 is added
It should be also possible to delete lines, like here: Line 30 was deleted, by pressing "-"-Button.
As I wrote at the beginning, it is possible, that there was such a question, but I couldn't find anything (probably, because I do not now the keywords or I was looking with a wrong ones).
How such window can be done? The only idea I have is to draw a new window after every +/-.
Addition: Code (not working in the part of changing the number of rows).
import javax.swing.*;
import java.awt.event.*;
public class Test extends JFrame {
public Test() {
setSize(200, 600);
JButton plusButton[] = new JButton[100];
JButton minusButton[] = new JButton[100];
JTextField fields[] = new JTextField[100];
JPanel panel1 = new JPanel();
for (int i=0; i<plusButton.length; i++) {
plusButton[i]=new JButton("+");
minusButton[i]=new JButton("-");
fields[i] = new JTextField("Text "+ i);
}
for (int i=1; i<4; i++) {
panel1.add(plusButton[i*10]);
plusButton[i*10].setActionCommand("add after " +String.valueOf(i));
panel1.add(minusButton[i*10]);
minusButton[i*10].setActionCommand("remove " +String.valueOf(i));
panel1.add(fields[i*10]);
}
panel1.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
this.getContentPane().add(panel1);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e) {
for (int i=0; i<100; i++) {
String stand1 = "add after "+String.valueOf(i);
String stand2 = "remove "+String.valueOf(i);
if (stand1.equals(e.getActionCommand())) {
//add "row" of elements
panel1.add(plusButton[i]);
plusButton[i+1].setActionCommand("add");
panel1.add(minusButton[i+1]);
minusButton[i+1].setActionCommand("remove");
panel1.add(fields[i+1]);
} else if (stand2.equals(e.getActionCommand())) {
//delete "row" of elements
}
}
}
public static void main(String[] args) {
Test a = new Test();
}
}
The Problem, that is obvious -- when I want to add 2 rows (i think it is proper definition) of buttons after button 20, there will be an doubling of numbers. As a solution I see here a creation of a new panel for each new row. But it is sounds wrong for me.
P.S. Unfortunately I do not have time to end this topic or to post a working example. I actually found some kind of solution, beginning from the Question here, on Stack Overflow:
Adding JButton to JTable as cell.
So, in case somebody will be looking for such topic, it should sounds like "jButton in jTable".
There are multiple GUI frameworks for Java. First decide which one you wanna use.
As for your particular query
Add functionality to the + and - such that it will create an instance of a field object (that line with parameters as you call them) or destroy that particular instance of the object.
+ is clicked -> Create new object on consecutive line and increase the pointer-count(?) of the following fields.
- is clicked -> Call destructor for the particular object and decrease the pointer-count of the following fields.

Issues creating java GUI with while loop

I am creating a java GUI which is a fortune teller. The GUI will spit out one of twelve fortunes every time you click the "get my fortune" button, the strings will never repeat back to back, can can repeat later after other strings have gone before it. I have made already for the most part. But now I am having some trouble creating the while loops to display the strings without repeating. I have looked at my book which didn't really help. If you guys could point me in the right direction,it would be much appreciated. Thanks!
I entered all of the code so you can see the variables used. But my question starts at class RndButtonListener.
package FortuneTellerRunner;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
/**
*
* #author a3cal_000
*/
class FortuneTellerFrame extends JFrame
{
final private JPanel mainPnl, titlePnl, displayPnl, buttonPnl, imagePnl;
final private JButton quitBtn, rndBtn;
final private JLabel titleLbl, iconLbl;
final private JTextArea displayTa;
final private JScrollPane scroller;
public String[] fortune = new String [12];
int newIndex, oldIndex;
private static final int HEIGHT = 250;
private static final int WIDTH = 450;
public FortuneTellerFrame()
{
setSize(WIDTH, HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainPnl = new JPanel();
mainPnl.setLayout(new BorderLayout());
displayPnl = new JPanel();
buttonPnl = new JPanel();
titlePnl = new JPanel();
ImageIcon icon = new ImageIcon("FortuneTellerIcon.JPEG");
iconLbl = new JLabel(icon);
titleLbl = new JLabel("Fortune Teller!");
displayTa = new JTextArea();
imagePnl = new JPanel();
scroller = new JScrollPane();
// Create the layout of the title panel
titlePnl.setLayout(new GridLayout(2,1));
add(mainPnl);
// Set the label to the panel.
titlePnl.add(titleLbl);
titlePnl.add(iconLbl);
// add the panel to the main panel.
mainPnl.add(titlePnl, BorderLayout.NORTH);
mainPnl.add(scroller, BorderLayout.CENTER);
mainPnl.add(displayTa, BorderLayout.CENTER);
// Create the "Get my fortune button.
rndBtn = new JButton("Get My Fortune!");
quitBtn = new JButton("Quit");
// Add the buttons to the buttonPnl in grid layout.
buttonPnl.add(rndBtn);
buttonPnl.add(quitBtn);
// Create the grid layout for the button panel.
buttonPnl.setLayout( new GridLayout(1, 2));
// Add the button panel to the grid layout, South.
mainPnl.add(buttonPnl, BorderLayout.SOUTH);
ActionListener listener = new RndButtonListener();
rndBtn.addActionListener(listener);
quitBtn.addActionListener(listener);
}
class RndButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
fortune[0] = "He who throws dirt is losing ground.";
fortune[1] = "You will find the love of your life in food.";
fortune[2] = "Do or do not, there is no try.";
fortune[3] = "Tomorrow is a better day to try anything of importance.";
fortune[4] = "Life's not about how hard you can hit, but how hard you can get hit and keep moving forward.";
fortune[5] = "You can't be late until you show up.";
fortune[6] = "If you think things can't get worse it's probably only because you lack sufficent imagination.";
fortune[7] = "If youre at the top it means you have further to fall.";
fortune[8] = "Even in last place, youre still in the race.";
fortune[9] = "The road to riches is paved on the failures of others.";
fortune[10] = "If you feel like your going no where, get off the treadmill.";
fortune[11] = "Thinking about going to the gym is just as good as going.";
Random rnd = new Random(fortune.length);
do
{
newIndex = rnd.nextInt(fortune.length);
}
while(newIndex == oldIndex);
do
{
System.out.println(fortune[newIndex]);
displayTa.append(fortune[newIndex] + "||");
displayTa.updateUI();
mainPnl.updateUI();
oldIndex = newIndex;
}
while(newIndex != oldIndex);
class QuitButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
System.exit(0);
}
}
}
}
}
The basic problem is you are re-creating the Random with the same seed each time, which is generally creating the same random sequence over and over again.
Instead try using...
do {
newIndex = (int) Math.round(Math.random() * (fortune.length - 1));
} while (newIndex == oldIndex);
You also don't need the second loop, it's just clutter that confuses the situation.
You may also find that...
displayTa.append(fortune[newIndex] + "\n");
produces nicer output (IMHO)
You may also wish to take a look at How to use Scroll Panes
Your program run fine, but this is a problem, fortune.length is a random seed which return me only 6 and 8 when I later called Random.nextInt().
Random rnd = new Random(fortune.length);
Do it this way
Random rnd = new Random();
and also consider the formatting solution given by MadProgrammer.
Random() gives you same number pattern. Try Random(System.currentTimeMillis()). It uses current time as seed, so you can get real random numbers.
I did something similar to this just today, so let's see if I can remember... I made an ArrayList of type int of how many items I had (fortunes)
ArrayList<Integer> fortuneSeq = new ArrayList<Integer>();
Then add in some numbers starting from 0 to code for the fortunes.
for(int i = 0; i < fortune.length; i++) {
fortuneSeq.add(i);
}
Then I used the shuffle() method from the Collections class to randomize the list.
Collections.shuffle(fortuneSeq);
After that, just loop through to access the fortunes.
for(int i = 0; i < fortune.length; i++) {
System.out.println(fortune[fortuneSeq.get(i)]);
//...
}
Edit: Silly autocorrect, you don't like programmers.
Edit: Fixed some furtunes instead of fortunes and fixed println statement.

JTable, 3dimensional matrix and multiple panels

I am trying to fit data from a three-dimensional matrix into multiple JTables. I am using a layout that consists of multiple panels which are associated in a manner that gives me the layout I target (I'm not too familiar with GridBagLayout, so I'm putting my own layout together).
The problem is now that the tables are not displayed on the Frame, and I don't know if the problem are the multiple panels or if it's because I'm using a 3-dimensional matrix.
Using JTable works when not using fields of tables, layers, etc. - I assume sth. must go wrong there.
I'm very grateful for your help and tipps! Thanks a lot!
Here's my code:
import java.awt.*;
import javax.swing.*;
import javax.swing.JTable;
public class Tabellen extends JFrame{
private static final long serialVersionUID = 7526472295622776147L;
Container c;
JPanel p_tabellen;
JPanel[] p_tab;
JTable[] table;
String[] columnnames={};
String[][][] matrixStr;
double[][][] matrix;
public Tabellen(double [][][] matrix) {
//create a matrix of Strings from a double-matrix that can be read by the JTable constructor
this.matrix=matrix;
matrixStr = new String[matrix.length][matrix[0].length][matrix[0][0].length];
for (int dim=0; dim<matrix.length; dim++){
for (int zeile=0; zeile<matrix[0].length; zeile++){
for (int spalte=0; spalte<matrix[0][0].length; spalte++){
matrixStr[dim][zeile][spalte]= String.valueOf(matrix[dim][zeile][spalte]);
}
}
}
//create panels and Layouts
c = getContentPane();
p_tabellen= new JPanel(new GridLayout(matrix.length,1));
p_tab= new JPanel[matrix.length];
for (int p=0; p<matrix.length; p++){
p_tab[p]= new JPanel(new BorderLayout());
p_tabellen.add(p_tab[p]);
}
c.add(p_tabellen);
//create one table per panel
table = new JTable[matrix.length];
for (int dim=0; dim<matrix.length; dim++){
for (int zeile=0; zeile<matrix[0].length; zeile++){
for (int spalte=0; spalte<matrix[0][0].length; spalte++){
table[dim]= new JTable(matrixStr[dim],columnnames);
p_tab[dim].add(table[dim], BorderLayout.CENTER);
}
}
}
}
}
Input example:
public class TEST {
public static void main(String[] args) {
double [][][] matrix = {{{2,4,6},{7,8,9}},{{1,2,3},{3,4,8}},{{1,2,4},{5,7,9}},{{2,4,6},{7,8,9}},{{1,2,3},{3,4,8}},{{1,2,4},{5,7,9}},{{2,4,6},{7,8,9}},{{1,2,3},{3,4,8}},{{1,2,4},{5,7,9}},{{2,4,6},{7,8,9}},{{1,2,3},{3,4,8}},{{1,2,4},{5,7,9}},{{2,4,6},{7,8,9}},{{1,2,3},{3,4,8}},{{1,2,4},{5,7,9}}};
Tabellen d= new Tabellen(matrix);
d.setTitle("test");
d.setSize(1300,720);
d.setVisible(true);
d.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Assuming each of dim tables is meant to display zeile rows in spalte columns, create a List<TableModel> having dim entries, one for each table. Create a single JTable and update its model using setModel(). Let the user select the currently displayed model using an adjacent control. This example uses a JComboBox, but JSpinner is a good alternative. More on creating a TableModel may be found here.

Java: forcing a component to fill up the entire row in a GridLayout

I am writing a program that allows multiple users the share screenshots. Every time a user connects, everyone who is participating in the "room" (a bunch of users that are able to receive screen shots from one another) becomes able to see a screen shot that the user takes. To be able to see the screen shot, the frame needs to split itself up so that there is a dedicated space for that user's screen shots.
I decided to use a GridLayout because it splits components into equally-sized rectangles which is what I am looking for. The layout does exactly what I need it to, except there is one problem. If I my GridLayout configured that there are two rows and columns, the bottom-most row will still be split into two columns, even when there is only a single component. This is expected behavior, but is there a walk-around, preferably without using a different layout? I really like the simplicity of GridLayout. I have considered using a BorderLayout, but it is limited because there is a set amount of spaces where I can place items.
The format of the pictures wasn't supported, so I could not embed them into this question.
Here is how the frame looks like it is full. I substituted the actual screen shots for buttons because I am just testing.
http://cl.ly/0N311g3w061P1B0W1T3s/Screen%20shot%202012-05-13%20at%204.23.25%20PM.png
Now here is how it looks when I remove a button from the bottom-most row:
http://cl.ly/2j3Z0V1r3w1S3F160j05/Screen%20shot%202012-05-13%20at%204.23.41%20PM.png
Here is how I would want the bottom-most row to look:
http://cl.ly/0J2R2y2L06151F0k0Y0i/Screen%20shot%202012-05-13%20at%204.24.11%20PM.png
How can I make the bottom-most row look like that? Keep in mind I still want the other rows to have two columns, but I only want the bottom-most one to have one column.
Thanks!
To my knowledge, you can't. GridLayout is done this way.
But GridBagLayout will do a beautiful job for your program.
Take a look at this small demo that lays out buttons in rows and columns.
(Click on a button to remove it).
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Test4 {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
final JPanel root = new JPanel(new GridBagLayout());
frame.add(root);
frame.setSize(600, 600);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Timer t = new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
final JButton b = new JButton("Hello" + root.getComponentCount());
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
root.remove(b);
updateConstraints(root);
}
});
root.add(b);
updateConstraints(root);
}
});
t.start();
}
});
}
protected static void updateConstraints(JPanel root) {
if (!(root.getLayout() instanceof GridBagLayout)) {
System.err.println("No a gridbaglayout");
return;
}
GridBagLayout layout = (GridBagLayout) root.getLayout();
int count = root.getComponentCount();
int col = (int) Math.round(Math.sqrt(count));
int row = (int) Math.ceil((double) count / col);
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.BOTH;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
int index = 0;
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
gbc.gridx = j;
gbc.gridy = i;
boolean last = index + 1 == count;
if (last) {
gbc.gridwidth = col - j;
}
Component c = root.getComponent(index);
layout.setConstraints(c, gbc);
if (last) {
break;
}
index++;
}
}
root.doLayout();
}
}
I decided to go with a slightly different approach. Since the separate screens are laid out really nicely using GridLayout when there are an even amount of screens, I decided to simply split up the screens into pages if there is an odd amount of screens.
I think you want to use the GridBagLayout - check out the visual guide to layouts
In particular, with a GridBagLayout, you add components with a GridBagConstraints. This allows you to specify where each component should be put, but also what weight each component should have - e.g. see the GridBagLayout tutorial.

Runtime alignment of JComponents + chaining to RowFilters

I'm currently working on a rather complex application. My job is to build parts of the GUI.
The main area is derived for JTable and contains all application relevant data. There are a few elements on top of the Table, that allow the user to control the way the data is shown in the table.
The options relevant to the task at hand are:
Changing of number of columns,
Independently changing of width of columns (not by means of JTableHeader) and
Entering one filter term per column to select specific rows of the data.
The main goal in this szenario is to create a Component (probably JTextField) for every column in the current viewsetting, which is accuratly aligned with that column (although it changes size at runtime).
First question:
The alignment doesn't work. I can't get the width of the TextFields to match the width of the columns.
How do i get it to work?
Second problem:
I want the individual filters to be chained. That is, if the user decides to enter more then one filter string, all of them should be evaluated for their respective columns and only the rows that match all filters should be shown. So far the input in a second TextField delets the first filter (which is working decently using RowFilter.regexFilter).
How do i get this to work?
Please let me know, which code snippets could be useful to you and i will be glad to post them.
Thanks in advance for any help given.
Regards, DK
I can't get the width of the
TextFields to match the width of the
columns
This example should get you started:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class TableFilterRow extends JFrame implements TableColumnModelListener
{
private JTable table;
private JPanel filterRow;
public TableFilterRow()
{
table = new JTable(3, 5);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
getContentPane().add( scrollPane );
table.getColumnModel().addColumnModelListener( this );
// Panel for text fields
filterRow = new JPanel( new FlowLayout(FlowLayout.CENTER, 0 , 0) );
for (int i = 0; i < table.getColumnCount(); i ++)
filterRow.add( new JTextField("" + i) );
columnMarginChanged( new ChangeEvent(table.getColumnModel()) );
getContentPane().add(filterRow, BorderLayout.NORTH);
}
// Implement TableColumnModelListener methods
// (Note: instead of implementing a listener you should be able to
// override the columnMarginChanged and columMoved methods of JTable)
public void columnMarginChanged(ChangeEvent e)
{
TableColumnModel tcm = table.getColumnModel();
int columns = tcm.getColumnCount();
for (int i = 0; i < columns; i ++)
{
JTextField textField = (JTextField)filterRow.getComponent( i );
Dimension d = textField.getPreferredSize();
d.width = tcm.getColumn(i).getWidth();
textField.setPreferredSize( d );
}
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
filterRow.revalidate();
}
});
}
public void columnMoved(TableColumnModelEvent e)
{
Component moved = filterRow.getComponent(e.getFromIndex());
filterRow.remove(e.getFromIndex());
filterRow.add(moved, e.getToIndex());
filterRow.validate();
}
public void columnAdded(TableColumnModelEvent e) {}
public void columnRemoved(TableColumnModelEvent e) {}
public void columnSelectionChanged(ListSelectionEvent e) {}
public static void main(String[] args)
{
JFrame frame = new TableFilterRow();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
only the rows that match all filters
should be shown
Read the JTable API and follow the link to the Swing tutorial on "How to Use Tables" where you will find the TableFilterDemo. You can easily modify the code to use "and" filters. The code would be something like:
// rf = RowFilter.regexFilter(filterText.getText(), 0);
List<RowFilter<Object,Object>> filters = new ArrayList<RowFilter<Object,Object>>(2);
filters.add(RowFilter.regexFilter(filterText.getText(), 0));
filters.add(RowFilter.regexFilter(filterText.getText(), 1));
rf = RowFilter.andFilter(filters);
This examples shares a single text field looking for the same string in multiple columns. You would obviously use your individual text fields.

Categories

Resources