I have a problem with JTable/JScrollPane. My data table is not refreshing/updating. I am using DefultTableModel and according to the code everything is fine and I don't have any errors. Also I have a table with paging and that's why I am using action listeners and buttons "prev" and "next". I am passing from other function to function that is coded in class where is JTable. Problem is that I fill arrays which contains data for table but table won't update/refresh it. Here is my code. Thanks advance.
BIG EDIT Old code was removed. I added new codes that will help you guys/girls to understand problem that I have. Hope that this will help. Regards.
First here is class that show gui:
import javax.swing.*;
public class Glavni {
public static void main(String[] args) {
// TODO Auto-generated method stub
SwingUtilities.invokeLater(new Runnable() {
public void run() {
gui Scanner = new gui();
Scanner.setVisible(true);
}
});
}
}
Second here is class that pass String to gui class that contains jtable
public class passDatatoTable {
public void passData(){
String str1,str2,str3,str4;
gui SendStringsToGUI = new gui();
for (int i =0;i<=10;i++){
str1="Column 1 of row: "+i;
str2="Column 2 of row: "+i;
str3="Column 3 of row: "+i;
str4="Column 4 of row: "+i;
SendStringsToGUI.WriteMonitorData(str1, str2, str3, str4);
}
}
}
Next here is declaration of gui (contructor):
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class gui extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
String[][] data = new String[100][4];
String[] columnNames = new String[]{
"IP", "PC_NAME", "ttl", "db"
};
DefaultTableModel model = new DefaultTableModel(data,columnNames);
JTable table = new JTable(model);
JScrollPane scrollPane = new JScrollPane(table);
int i=0;
public void WriteMonitorData (String IP, String PC_NAME, String ttl, String gw)
{
System.out.println(IP);//just for testing (check if data was passed)
model.setValueAt(IP, i, 0);
model.setValueAt(PC_NAME, i, 1);
model.setValueAt(ttl, i, 2);
model.setValueAt(gw, i, 3);
i++;
model.fireTableDataChanged();
table.repaint();
scrollPane.repaint();
}
gui(){
JButton addData= new JButton("Add Data");
JButton next = new JButton("next");
JButton prev = new JButton("prev");
addData.addActionListener(this);
next.addActionListener(this);
prev.addActionListener(this);
JPanel panel = new JPanel(new BorderLayout());
JPanel buttonPanel = new JPanel();
buttonPanel.add(addData);
buttonPanel.add(prev);
buttonPanel.add(next);
panel.add(buttonPanel, BorderLayout.SOUTH);
panel.add(table.getTableHeader(), BorderLayout.PAGE_START);
panel.add(scrollPane, BorderLayout.CENTER);
getContentPane().add(panel);
}
Here is actionListeners:
public void actionPerformed(ActionEvent e) {
if ("Add Data".equals(e.getActionCommand())){
passDatatoTable passSomeData = new passDatatoTable();
passSomeData.passData();
}
if ("next".equals(e.getActionCommand())) {
Rectangle rect = scrollPane.getVisibleRect();
JScrollBar bar = scrollPane.getVerticalScrollBar();
int blockIncr = scrollPane.getViewport().getViewRect().height;
bar.setValue(bar.getValue() + blockIncr);
scrollPane.scrollRectToVisible(rect);
}
if ("prev".equals(e.getActionCommand())) {
Rectangle rect = scrollPane.getVisibleRect();
JScrollBar bar = scrollPane.getVerticalScrollBar();
int blockIncr = scrollPane.getViewport().getViewRect().height;
bar.setValue(bar.getValue() - blockIncr);
scrollPane.scrollRectToVisible(rect);
}
}
Your first snippet shows this:
JTable table = new JTable(model);
but your gui() constructor shows:
JTable table = new JTable(data, columnNames);
You initiate the table twice. Once using the TableModel (JTable(TableModel tm)) the next using JTable(int rows,int cols) this is not good, initiate the JTable once in the constructor:
gui() {
DefaultTableModel model = new DefaultTableModel(data,columnNames);
JTable table = new JTable(model);
JScrollPane scrollPane = new JScrollPane(table);
JButton next = new JButton("next");
JButton prev = new JButton("prev");
next.addActionListener(this);
prev.addActionListener(this);
JPanel panel = new JPanel(new BorderLayout());
JPanel buttonPanel = new JPanel();
buttonPanel.add(prev);
buttonPanel.add(next);
panel.add(buttonPanel, BorderLayout.SOUTH);
panel.add(table.getTableHeader(), BorderLayout.PAGE_START);
panel.add(scrollPane, BorderLayout.CENTER);
getContentPane().add(panel);
}
UPDATE:
Here is an example that has a thread which will start 2.5 secinds after the UI is visible and change a value of the JTable:
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class Test extends JFrame {
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test().createAndShowUI();
}
});
}
private void createAndShowUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initComponents(frame);
frame.pack();
frame.setVisible(true);
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(2500);
} catch (InterruptedException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
model.setValueAt("hello", 0, 0);
}
});
}
}).start();
}
static DefaultTableModel model;
private void initComponents(JFrame frame) {
String data[][] = {
{"1", "2", "3"},
{"4", "5", "6"},
{"7", "8", "9"},
{"10", "11", "12"}
};
String col[] = {"Col 1", "Col 2", "Col 3"};
model = new DefaultTableModel(data, col);
JTable table = new JTable(model);
frame.getContentPane().add(new JScrollPane(table));
}
}
From what I understand from the comments and the question, you have first created a DefaultTableModel by passing the data as arrays in the constructor
String[][] data = new String[100][4];
String[] columnNames = new String[]{
"IP", "PC_NAME", "ttl", "db"};
DefaultTableModel model = new DefaultTableModel(data,columnNames);
and you try to modify the table afterwards by adjusting those arrays. That will never ever have any effect, as the DefaultTableModel does not use those arrays. This can be seen in the source code of that class
public DefaultTableModel(Object[][] data, Object[] columnNames) {
setDataVector(data, columnNames);
}
which in the end comes down to
protected static Vector convertToVector(Object[][] anArray) {
if (anArray == null) {
return null;
}
Vector<Vector> v = new Vector<Vector>(anArray.length);
for (Object[] o : anArray) {
v.addElement(convertToVector(o));
}
return v;
}
So all the elements of the array are copied into an internal Vector and the array is no longer used.
Solution: do not update the arrays but update the DefaultTableModel. That class provides all the API you need to add/remove data to/from it.
Related
public class BillDetailsPanel implements ActionListener {
JPanel panel;
int flag = 0;
JLabel lItemName, lPrice, lQty, ltax, lDisPrice;
JTextField price, qty, tax, disPrice;
JComboBox<String> itemName;
String[] bookTitles = new String[] { "Effective Java", "Head First Java",
"Thinking in Java", "Java for Dummies" };
JButton addBtn
public BillDetailsPanel() {
panel = new JPanel();
panel.setPreferredSize(new Dimension(900, 50));
FlowLayout layout = new FlowLayout(FlowLayout.CENTER, 5, 15);
panel.setLayout(layout);
// panel.setBackground(Color.GREEN);
lItemName = new JLabel("Item Name");
lPrice = new JLabel("Price");
lQty = new JLabel("Quantity");
ltax = new JLabel("Tax");
lDisPrice = new JLabel("Discount Price");
itemName = new JComboBox<String>(bookTitles);
itemName.addActionListener(this);
price = new JTextField(8);
// price.setEditable(false);
qty = new JTextField(4);
tax = new JTextField(5);
// tax.setEditable(false);
disPrice = new JTextField(8);
addBtn = new JButton("Add");
addBtn.addActionListener(this);
panel.add(lItemName);
panel.add(itemName);
panel.add(lPrice);
panel.add(price);
panel.add(lQty);
panel.add(qty);
panel.add(ltax);
panel.add(tax);
panel.add(lDisPrice);
panel.add(disPrice);
panel.add(addBtn);
panel.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
BillTablePanel btp=new BillTablePanel();
String[] data=new String[5];
data[0]=(String) itemName.getSelectedItem();
data[1]=price.getText();
data[2]=qty.getText();
data[3]=tax.getText();
data[4]=qty.getText();
btp.model.addRow(data);
btp.model.addRow(data);
System.out.println(data+"dataaaaaaaaaaaa");
}
}
}
public class BillTablePanel implements ActionListener{
public JPanel panel;
public JTable table;
public JScrollPane scrollPane, scrollPane1;
public DefaultTableModel model;
public int a=10;
String[] data=new String[5];
public BillTablePanel () {
panel = new JPanel();
panel.setLayout(null);
model = new DefaultTableModel();
String columnNames[] = { "Item Name", "Actual Price", "Qty", "Tax",
"Price" };
table = new JTable();
model.setColumnIdentifiers(columnNames);
table.setModel(model);
table.setFocusable(false);
scrollPane = new JScrollPane(table);
scrollPane.setBounds(0, 0, 850, 100);
panel.add(scrollPane);
}
<br>
public class TestClassFrame {
JFrame f;
BillDetailsPanel bill = new BillDetailsPanel();
BillTablePanel billTablePanel = new BillTablePanel();
public TestClassFrame() {
f = new JFrame("Zeon Systems");
f.setLayout(null);
bill.panel.setBounds(0, 0, 900, 100);
f.add(bill.panel);
billTablePanel.panel.setBounds(0, 100, 900, 500);
f.add(billTablePanel.panel);
f.pack();
f.setSize(900, 550);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
new TestClassFrame();
}
}
Problem with this code is The class Bill detais contain some text boxes and a button The BillTablepane class contain a Jtable I want to add the items from BillDetaisaPanel to the Jtable
On clicking the Jbutton which is not showing any error but the values are not inserting on it
The Full source is there Somebody please help me to find the logical error,
In your actionPerformed method, you're creating a new BillTablePanel object, at line (1), and then trying to add to the table model on line (2):
public void actionPerformed(ActionEvent e) {
BillTablePanel btp=new BillTablePanel(); // **** (1)
// ...
btp.model.addRow(data); // ***** (2)
But understand that that new BillTablePanel is just that, a completely new and distinct object, one completely unrelated to the one that is displayed. To change the state of the displayed data, you must call methods on the displayed BillTablePanel object, not on a new one that you create just for the actionPerformed method.
For example, here's a similar minimal program:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class TableExample extends JPanel {
private HoldsTable holdsTable = new HoldsTable();
private JTextField lastNameField = new JTextField(10);
private JTextField firstNameField = new JTextField(10);
public TableExample() {
JPanel fieldPanel = new JPanel();
fieldPanel.add(new JLabel("Last Name:"));
fieldPanel.add(lastNameField);
fieldPanel.add(new JLabel("First Name:"));
fieldPanel.add(firstNameField);
JPanel buttonPanel = new JPanel();
buttonPanel.add(new JButton(new AbstractAction("Your Action") {
#Override
public void actionPerformed(ActionEvent evt) {
HoldsTable ht = new HoldsTable(); // creates a new reference -- bad!
String lastName = lastNameField.getText();
String firstName = firstNameField.getText();
ht.addName(lastName, firstName);
}
}));
buttonPanel.add(new JButton(new AbstractAction("My Action") {
#Override
public void actionPerformed(ActionEvent evt) {
// HoldsTable ht = new HoldsTable();
String lastName = lastNameField.getText();
String firstName = firstNameField.getText();
// ht.addName(lastName, firstName);
holdsTable.addName(lastName, firstName); // use the ref to the displayed object
}
}));
setLayout(new BorderLayout());
add(holdsTable, BorderLayout.CENTER);
add(fieldPanel, BorderLayout.PAGE_START);
add(buttonPanel, BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
TableExample mainPanel = new TableExample();
JFrame frame = new JFrame("TableExample");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class HoldsTable extends JPanel {
private static final String[] COL_NAMES = { "Last Name", "First Name" };
private DefaultTableModel model = new DefaultTableModel(COL_NAMES, 0);
private JTable table = new JTable(model);
public HoldsTable() {
setLayout(new BorderLayout());
add(new JScrollPane(table));
}
public void addName(String lastName, String firstName) {
String[] row = { lastName, firstName };
model.addRow(row);
}
}
Your program creates a new non-displayed object, and changes its properties, similar to this code in my program above:
#Override
public void actionPerformed(ActionEvent evt) {
HoldsTable ht = new HoldsTable(); // creates a new reference --
// bad!
String lastName = lastNameField.getText();
String firstName = firstNameField.getText();
ht.addName(lastName, firstName);
}
}));
But since the object whose state is being changed, here ht, but in your code its btp, is not the one that is displayed, nothing will show.
The correct way is shown in the other action:
#Override
public void actionPerformed(ActionEvent evt) {
// HoldsTable ht = new HoldsTable();
String lastName = lastNameField.getText();
String firstName = firstNameField.getText();
// ht.addName(lastName, firstName);
holdsTable.addName(lastName, firstName); // use the ref to the
// displayed object
}
I create a field of the GUI view that holds the JTable, here holdsTable and call a method on it. Since holdsTable is visible, changes in its state will be shown in the program (here the JTable).
I'm wondering how I would add a unique(changing one does't change all of them) row to a JTable with a JButton
final DefaultTableModel mod = new DefaultTableModel();
JTable t = new JTable(mod);
mod.addColumn{" "};
mod.addColumn{" "};
JButton b = new JButton
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//How would I make tf unique by producing a different variable every row if changed
final JTextField tf = new JTextField();
final Object[] ro = {"UNIQUE ROW", tf};
mode.addRow(ro);
}):
tf.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//s change to an other variable every row added
String s = tf.getText();
}):
You seem close, but you don't want to add JTextField's to a table row. Instead add the data it holds. For example:
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
public class UniqueRow extends JPanel {
public static final String[] COLS = {"Col 1", "Col 2"};
private DefaultTableModel model = new DefaultTableModel(COLS, 0);
private JTable table = new JTable(model);
private JTextField textField1 = new JTextField(10);
private JTextField textField2 = new JTextField(10);
public UniqueRow() {
add(new JScrollPane(table));
add(textField1);
add(textField2);
ButtonAction action = new ButtonAction("Add Data");
textField1.addActionListener(action);
textField2.addActionListener(action);
add(new JButton(action));
}
private class ButtonAction extends AbstractAction {
public ButtonAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
// get text from JTextField
String text1 = textField1.getText();
String text2 = textField2.getText();
// create a data row with it. Can use Vector if desired
Object[] row = {text1, text2};
// and add row to JTable
model.addRow(row);
}
}
private static void createAndShowGui() {
UniqueRow mainPanel = new UniqueRow();
JFrame frame = new JFrame("UniqueRow");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
My problem is that a JTable does not update when I select my combobox. The program I present below should delete all data (data = null;), when LA is selected. The table does not update.
public class minimumExample extends JFrame {
private JTabbedPane tabbedPane;
private FilteredTabPanel filteredTabPanel;
public void createTabBar() {
tabbedPane = new JTabbedPane(JTabbedPane.TOP);
filteredTabPanel = new FilteredTabPanel();
tabbedPane.addTab("Test", filteredTabPanel.createLayout());
add(tabbedPane);
tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
}
private void makeLayout() {
setTitle("Test App");
setLayout(new BorderLayout());
setPreferredSize(new Dimension(1000, 500));
createTabBar();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setVisible(true);
}
public void start() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
makeLayout();
}
});
}
public static void main(String[] args) throws IOException {
minimumExample ex = new minimumExample();
ex.start();
}
public class FilteredTabPanel extends JPanel {
private JPanel selectionArea;
private JLabel lCity;
private JComboBox cityBox;
private JTable filterTable;
String[] columnNames = {"Cities"};
String[][] data = {
{"NY"}, {"NY"}, {"NY"}, {"NY"}, {"LA"}, {"LA"},{"Columbia"},{"DC"},{"DC"},{"DC"},{"DC"},{"DC"},{"DC"}
};
private JScrollPane scrollPane;
public JPanel createLayout() {
JPanel panel = new JPanel(new GridLayout(0, 1));
//add panels to the layout
panel.add(addButtons());
panel.add(showTable());
repaint();
revalidate();
return panel;
}
public JPanel addButtons(){
selectionArea = new JPanel(new FlowLayout(FlowLayout.LEFT));
lCity = new JLabel("City");
String[] fillings = {"NY", "LA", "Columbia", "DC"};
cityBox = new JComboBox(fillings);
cityBox.addActionListener(new ActionListener() {
private String cityFilter;
#Override
public void actionPerformed(ActionEvent arg0) {
//2. get data
cityFilter = cityBox.getSelectedItem().toString();
if(cityFilter.equals("LA")) {
data = null;
}
showTable();
repaint();
}
});
selectionArea.add(lCity);
selectionArea.add(cityBox);
selectionArea.repaint();
return selectionArea;
}
private JScrollPane showTable() {
filterTable =new JTable(data, columnNames);
filterTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
scrollPane = new JScrollPane(filterTable);
scrollPane.repaint();
scrollPane.validate();
return scrollPane;
}
}
}
As you can see the table does not update. Any recommendations what I am doing wrong?
Instead of creating new instance of you objects by calling showTable (which never get added to the screen in any way), which is just going to completely mess up your object references, try resetting the TableModel, for example...
if ("LA".equals(cityFilter)) {
filterTable.setModel(new DefaultTableModel(null, columnNames));
}
Take a closer look at How to Use Tables for more details
I am making a chat application in Java. They can add friends and chat with them.
Here is my add friend JFrame idea:
I tried to google search Multi jpanel in one jscrollpane but I found nothing. I ended up with custom JTable. I want to create a custom JTable which have JLabels in different position in each slot. Users can just select a slot in JTable, then they can use the JButton below to chat with them.
Is it possible to do this in Java. Is yes, please share your idea. Thanks.
Here is a proposal. But it contains some flaws yet
Size propagation is fiexed (may be better client or server based sizing)
No event delegation to underlying Component
Performance, because heavyweight panel instances are created frequently inside paint loop
But here is how it can be done. The code is separated into parts.
A value class
Just a simple class to represent the date inside your panels for each cell.
class Value {
public final String text;
public final boolean flag;
public Value(String text, boolean flag) {
this.text = text;
this.flag = flag;
}
}
My individual panel class
The representation can be modelled within a gui editor like google's window builder. This panel makes use of the value and displays it accordingly.
public class MyPanel extends JPanel {
public MyPanel(Value v) {
JLabel lblNewLabel = new JLabel(v.text);
add(lblNewLabel);
JCheckBox chckbxSomeValue = new JCheckBox("some value");
chckbxSomeValue.setSelected(v.flag);
add(chckbxSomeValue);
}
}
A table cell renderer class
Just returns some panel instance showing up the desired values.
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
class MyPanelCellRenderer implements TableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
return new MyPanel((Value)value); // maybe performance problem
}
}
A custom table model
import javax.swing.table.DefaultTableModel;
class MyTableModel extends DefaultTableModel {
public MyTableModel() {
super(new Object[][] {
new Object[] { 1, new Value("asdf", true) },
new Object[] { 2, new Value("qwer", false) } },
new String[] {"Id", "MyPanel" });
}
Class[] columnTypes = new Class[] { Integer.class, Value.class };
MyTableModel(Object[][] data, Object[] columnNames) {
super(data, columnNames);
}
public Class getColumnClass(int columnIndex) {
return columnTypes[columnIndex];
}
}
A frame class
import java.awt.BorderLayout;
public class MyFrame {
JFrame frame;
private JTable table;
public MyFrame() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
table = new JTable();
table.setModel(new MyTableModel());
table.setFillsViewportHeight(true);
table.getColumnModel()
.getColumn(1)
.setCellRenderer(new MyPanelCellRenderer());
table.setRowHeight(40); // static sizing
JScrollPane scrollPane = new JScrollPane();
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
scrollPane.setViewportView(table);
}
}
Main Function
import java.awt.EventQueue;
public class MyApp {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MyFrame window = new MyFrame();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
The final result
The panel MyPanel is created using eclipse and google's window builder
This is a completely different approach using neither a table nor a list. It uses panels as items arranged as a list inside of another panel. This solution doesn't requires any further modification to delegate any events to the underlying controls. The events are processed natively. The idea comes from this post. I have separated the logic into two parts for now.
JPanelList class
This class is a JPanel and maintains a list of such. ATM they can be added using the methods addPanel and addPanels.
public class JPanelList extends JPanel {
private static final long serialVersionUID = 1L;
private JPanel mainList;
private List<JPanel> panels = new ArrayList<JPanel>();
public JPanelList() { this(new ArrayList<JPanel>()); }
public JPanelList(List<JPanel> panels) {
setLayout(new BorderLayout());
mainList = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1;
gbc.weighty = 1;
mainList.add(new JPanel(), gbc);
add(new JScrollPane(mainList));
addPanels(panels);
}
public void addPanels(List<JPanel> panels) {
for (JPanel panel : panels)
addPanel(panel);
}
public void addPanel(JPanel panel) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
mainList.add(panel, gbc, 0);
panels.add(panel);
validate();
repaint();
}
}
JListFrame test class with main function
public class JPanelListFrame {
private JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
JPanelListFrame window = new JPanelListFrame();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public JPanelListFrame() {
frame = new JFrame();
frame.setBounds(100, 100, 210, 192);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanelList panelList = new JPanelList();
frame.getContentPane().add(panelList, BorderLayout.CENTER);
JButton btnAddMypanel = new JButton("Add MyPanel");
btnAddMypanel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// just add a MyPanel with a Value containing a
// "asdf" and a random boolean
panelList.addPanel(new MyPanel(new Value("asdf",
(int) (2 * Math.random()) % 2 == 0)));
}
});
panelList.add(btnAddMypanel, BorderLayout.SOUTH);
}
}
One drawback with this solution is that the selection mechanics are lost. When selecting elements is a key requirement maybe a JList might be more appropriate. Another thing is that the items are not rendered as they would be rendered inside a JList or JTable e.g. using fancy borders. This can be solved by somehow adding a border decorator before adding the panels into the mainList of the JPanelList.
I have to program that takes ip Addresses from a file and outputs the country its in onto a JTable. I have no errors but when i click the button the JTable doesn't open up. How do i make the JTable open up?
package org.koushik.javabrains;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.io.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import net.webservicex.GeoIP;
import net.webservicex.GeoIPService;
import net.webservicex.GeoIPServiceSoap;
public class IPLocationFinder {
public static void main(String[] args) {
final JFileChooser filechooser = new JFileChooser();
filechooser.setVisible(false);
final JTable jt;
final String[] columns= {"IP address","Country"};
final String[][] data = {{}};
final DefaultTableModel model = new DefaultTableModel(data, columns);
jt = new JTable(model);
jt.setPreferredScrollableViewportSize(new Dimension(450, 60));
jt.setFillsViewportHeight(true);
JScrollPane jps = new JScrollPane();
jt.add(jps);
final JFrame frame = new JFrame();
frame.setSize(500,500);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new GridBagLayout());
frame.getContentPane().add(panel, BorderLayout.CENTER);
GridBagConstraints c = new GridBagConstraints();
JButton b1 = new JButton("Start");
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(10,10,10,10);
panel.add(b1, c);
frame.setBounds(400,150,600,200);
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
new IPLocationFinder();
BufferedReader inputStream = null;
try {
inputStream = new BufferedReader(new FileReader("C:/IP Addresses/ip.txt"));
String l;
try {
while ((l = inputStream.readLine()) != null) {
String ipAddress = l;
GeoIPService ipService = new GeoIPService();
GeoIPServiceSoap geoIPServiceSoap = ipService.getGeoIPServiceSoap();
GeoIP geoIp = geoIPServiceSoap.getGeoIP(ipAddress);
model.addRow(new String[][]{{"Column 1", geoIp.getCountryName()}});
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
};
b1.addActionListener(actionListener);
}
}
You have several problems:
You never add the JTable to your panel.
You're adding a JScrollPane to your JTable when it should be the other way around. The JScrollPane should have its view set to the scrollable component, which in this case is the JTable. Otherwise, as your table's rows increase, the elements above it are simply going to be pushed up.
You've added an empty row to your table by saying final String[][] data = { {} };. When you start adding rows, you'll have a blank row to start. Therefore, you should remove the inner curly braces.
You should be aware that your JTable data is being prescribed as a 2D String array and although you're technically adding the data correctly, it's going to show up as an address in your first column:
To fix the above issue, change your addRow data to a 2D array such as model.addRow(new String[] { "Column 1", "Country 1" });
Below is a simplified, corrected version:
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class IPLocationFinder {
public static void main(String[] args) {
final String[] columns = { "IP address", "Country" };
final String[][] data = {};
final DefaultTableModel model = new DefaultTableModel(data, columns);
final JTable jt = new JTable(model);
final JFrame frame = new JFrame();
final JScrollPane jps = new JScrollPane(jt);
final JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
JButton b1 = new JButton("Start");
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(10, 10, 10, 10);
panel.add(b1, c);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel, BorderLayout.NORTH);
frame.getContentPane().add(jps, BorderLayout.CENTER);
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
model.addRow(new String[] { "Column 1", "Country 1" });
}
};
b1.addActionListener(actionListener);
frame.pack();
frame.setVisible(true);
}
}
I'm gessing you're using a panel to show the jtable, however as you can notice, there's no a panel.add(jt); line.
So, go ahead and add that line inside the Action
EDIT
As #Braj comment, the jt must be added to the scroll. Then instead add the JTable, add the JScroll.
panel.add(jsp);