I am trying to update my table, but it is not working. The table does not show up until the entire program calling it is done. How can I change this? Upon opening the window, I would like to fill the JTable with data. If I stop the execution of the code, the table is filled with data. Do I need a thread? How would I use one correctly? My code is below.
public class TestGUI extends DefaultTableCellRenderer implements TeststepEventListener {
public JFrame frame;
private JTable testcase_table;
private JTable teststep_table;
/**
* Create the application.
*/
public TestGUI() {
initialize();
frame.setVisible(true);
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JProgressBar progressBar = new JProgressBar();
progressBar.setBounds(50, 68, 700, 14);
frame.getContentPane().add(progressBar);
JTextPane txtpnAutomotiveHmi = new JTextPane();
txtpnAutomotiveHmi.setText("Automotive HMI");
txtpnAutomotiveHmi.setBounds(362, 21, 205, 20);
frame.getContentPane().add(txtpnAutomotiveHmi);
testcase_table = new JTable();
testcase_table.setBounds(50, 125, 350, 426);
frame.getContentPane().add(testcase_table);
teststep_table = new JTable();
teststep_table.setBounds(399, 125, 350, 426);
frame.getContentPane().add(teststep_table);
}
private boolean testcase = true;
#Override
public void myEventOccurred(TeststepEvent event) {
TeststepData data = event.data();
if (testcase) {
set_values(data.getDoc(), data.getTestcase());
}
testcase = false;
}
private int i = 0;
LinkedList names = new LinkedList();
private void set_values(Document doc, int testcase) {
frame.setTitle("Wuratbrot" + i);
i++;
Element element = doc.getRootElement();
names.clear();
if (element != null) {
List<Element> testCases = element.getChildren();
//testcase_table.removeAll();
//String[] title = {"Testcases"};
for (Element testCase : testCases) {
names.add(testCase.getAttributeValue("name"));
}
DisplayData(names);
}
testcase_table.revalidate();
frame.validate();
}
private void DisplayData(List<String> Testcases) {
DefaultTableModel aModel = new DefaultTableModel() {
//setting the jtable read only
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
//setting the column name
Object[] tableColumnNames = new Object[1];
tableColumnNames[0] = "TestCases";
aModel.setColumnIdentifiers(tableColumnNames);
if (Testcases == null) {
testcase_table.setModel(aModel);
return;
}
Object[] objects = new Object[1];
ListIterator<String> lstrg = Testcases.listIterator();
//populating the tablemodel
while (lstrg.hasNext()) {
String newcus = lstrg.next();
objects[0] = newcus;
aModel.addRow(objects);
}
//binding the jtable to the model
testcase_table.setModel(aModel);
}
}
SwingWorker is intended for this. Data acquisition can take place asynchronously in doInBackground(), while process() safely updates the TableModel on the event dispatch thread via publish(). In particular, see the section entitled Sample Usage and this tutorial. Moreover, DefaultTableModel fires the appropriate update events for which the JTable listens. No additional code should be required. As an aside, use layouts rather than setBounds().
You need the function fireTableDataChanged. You should call it upon your table model after changing the values of table cells.
Related
I am having an unexpected behavior with the Java GUI. I want to create a JScrollPane containing a JTable then add this JScrollPane to a Frame.
Here is the code :
public class UrlsScrollPanel extends JScrollPane {
private static final long serialVersionUID = 1L;
public UrlsScrollPanel() {
//setup urls and collections
ArrayList<URL> urls = URL.getAll();
ArrayList<Collection> collections = new ArrayList<>();
for(URL url : urls) collections.add(new Collection(url));
//table
String[] columns = {
"database",
"status",
"consumption",
"last snapshot date",
"last message",
"details",
"stop collect"
};
AbstractTableModel dataModel = new AbstractTableModel() {
private static final long serialVersionUID = 1L;
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
System.out.printf("row: %d, column: %d \n", rowIndex, columnIndex); //is never called.
URL url = urls.get(rowIndex);
Collection collection = collections.get(rowIndex);
ArrayList<Message> lastMessages = collection.getLastSnapshot().getMessages();
Message lastMessage = lastMessages.get(lastMessages.size() - 1);
if(columnIndex == 0) return url.toString();
if(columnIndex == 1) return collection.getStatus();
if(columnIndex == 2) return ConsumptionChart.getChartPanel(collection);
if(columnIndex == 3) return collection.getLastSnapshot().getDate();
if(columnIndex == 4) return String.format("[ %s ] %s", lastMessage.getDate(), lastMessage.getBody());
return "Comming soon.";
}
#Override
public int getRowCount() {
return urls.size();
}
#Override
public int getColumnCount() {
return columns.length;
}
#Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
JTable table = new JTable(dataModel);
add(table);
setBackground(Color.red);
setSize(500, 500);
}
}
And here is how I call it :
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setVisible(true);
frame.setResizable(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH );
frame.setLocationRelativeTo(null);
UrlsScrollPanel panel = new UrlsScrollPanel();
frame.add(panel, BorderLayout.CENTER);
SwingUtilities.updateComponentTreeUI(frame);
}
The result is a red square blinking at the top left of the frame then disappearing immediately. Also the dataModel seems to be never called.
Any help in what I am doing wrong is much appreciated, thanks for your time!
Don't extend JScrollPane. Instead, use your table to construct a JScrollPane:
frame.add(new JScrollPane(table), BorderLayout.CENTER);
The approach is described here; a complete example is shown here; an alternative approach using setViewportView() is examined here.
Are these two not similar?
JScrollPane panel = new JScrollPane(); panel.add(table);
…
JScrollPane panel = new JScrollPane(table);
No. As shown in How a Scroll Pane Works, the first formulation adds the table directly to the JScrollPane, replacing the JViewport component that occupies the central position in the ScrollPaneLayout and that would have been used to display the table. The second formulation invokes setViewportView(table) internally, which tells the scroll pane's JViewport what component to display.
I have two JTables one in main viewport and one in footer viewport, using JideScrollPane.
the problem is when the main JTable's view is customized, the footer JTable remains the
same, is there any way to synchronize their view?
thanks.
EDIT:
Here's a demo that will synch up the resizing of two tables that have similar columns. The idea is:
Create a custom TableColumnModelListener for each table's column model.
Upon resize, sync up the column widths. You'll have to disable the other listener temporarily, while this is happening.
For moving of columns, implement that logic in columnMoved(...) [left as an exercise]
This shows two-way synching:
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class JTableResizeColumnsDemo implements Runnable
{
JTable table1, table2;
TableColumnModelListener columnListener1, columnListener2;
Map<JTable, TableColumnModelListener> map;
public static void main(String[] args)
{
SwingUtilities.invokeLater(new JTableResizeColumnsDemo());
}
public void run()
{
Vector<String> names = new Vector<String>();
names.add("One");
names.add("Two");
names.add("Three");
table1 = new JTable(null, names);
table2 = new JTable(null, names);
columnListener1 = new ColumnChangeListener(table1, table2);
columnListener2 = new ColumnChangeListener(table2, table1);
table1.getColumnModel().addColumnModelListener(columnListener1);
table2.getColumnModel().addColumnModelListener(columnListener2);
map = new HashMap<JTable, TableColumnModelListener>();
map.put(table1, columnListener1);
map.put(table2, columnListener2);
JPanel p = new JPanel(new GridLayout(2,1));
p.add(new JScrollPane(table1));
p.add(new JScrollPane(table2));
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(p);
frame.setSize(300, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
class ColumnChangeListener implements TableColumnModelListener
{
JTable sourceTable;
JTable targetTable;
public ColumnChangeListener(JTable source, JTable target)
{
this.sourceTable = source;
this.targetTable = target;
}
public void columnAdded(TableColumnModelEvent e) {}
public void columnSelectionChanged(ListSelectionEvent e) {}
public void columnRemoved(TableColumnModelEvent e) {}
public void columnMoved(TableColumnModelEvent e) {}
public void columnMarginChanged(ChangeEvent e)
{
TableColumnModel sourceModel = sourceTable.getColumnModel();
TableColumnModel targetModel = targetTable.getColumnModel();
TableColumnModelListener listener = map.get(targetTable);
targetModel.removeColumnModelListener(listener);
for (int i = 0; i < sourceModel.getColumnCount(); i++)
{
targetModel.getColumn(i).setPreferredWidth(sourceModel.getColumn(i).getWidth());
}
targetModel.addColumnModelListener(listener);
}
}
}
You can apply an Observer pattern: the first JTable observes the second and vice versa. Then you add listners to both tables so that, when one is "customized", the other is notified. Basically, "being notified" consists in a method invocation that causes the update of the JTable.
In order to do that, you have two options:
You define a class Observer with a "register" method and a
"notify" method. When creating a JTable, you register it with the
Observer. Then, the listener you create and associate to each JTable
invoke the "notify" method of the observer, which informs all other
registered JTables of the change
You define a sort of "callback method" notify in the class that contains and declares the JTable. This "notify" method is invoked within the listner and updates the correct JTable. You can also create two methods: one for updating one JTable and one for the other JTable
Usually this is done by using the same model for different ui components. Sadly the JTable contains a bug that will cause problems when sharing the TableColumnModel.
But you can work around it using this JTable
class ShareableColumnModelTable extends JTable {
/**
* Fixes http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4816146 and
* more...
*
*/
#Override
public void columnMarginChanged(ChangeEvent e) {
if (isEditing()) {
removeEditor();
}
TableColumn resizingColumn = null;
if (tableHeader != null) {
resizingColumn = tableHeader.getResizingColumn();
}
if (resizingColumn != null) {
if (autoResizeMode == AUTO_RESIZE_OFF) {
resizingColumn.setPreferredWidth(resizingColumn.getWidth());
} else { // this else block is missing in jdk1.4 as compared to
// 1.3
TableColumnModel columnModel = getColumnModel();
/**
* Temporarily disconnects this column listener to prevent
* stackoverflows if the column model is shared between
* multiple JTables.
*/
columnModel.removeColumnModelListener(this);
try {
doLayout();
} finally {
columnModel.addColumnModelListener(this);
}
repaint();
return;
}
}
resizeAndRepaint();
}
}
With the ShareableColumnModelTableshowed above you can share one column model bettween multiple tables.
public static void main(String[] args) {
JFrame frame = new JFrame("Column Sync");
Container contentPane = frame.getContentPane();
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
splitPane.setResizeWeight(0.5d);
contentPane.add(splitPane);
JTable table1 = new ShareableColumnModelTable();
JTable table2 = new ShareableColumnModelTable();
TableColumnModel tableColumnModel = createTableColumnModel();
table1.setModel(createTableModel1());
table2.setModel(createTableModel2());
table1.setColumnModel(tableColumnModel);
table2.setColumnModel(tableColumnModel);
splitPane.setLeftComponent(new JScrollPane(table1));
splitPane.setRightComponent(new JScrollPane(table2));
showFrame(frame);
}
private static TableColumnModel createTableColumnModel() {
TableColumnModel tableColumnModel = new DefaultTableColumnModel();
TableColumn column1 = new TableColumn(0);
column1.setHeaderValue("1. column");
tableColumnModel.addColumn(column1);
TableColumn column2 = new TableColumn(1);
column2.setHeaderValue("2. column");
tableColumnModel.addColumn(column2);
return tableColumnModel;
}
private static TableModel createTableModel1() {
DefaultTableModel tableModel = new DefaultTableModel();
tableModel.setColumnCount(2);
tableModel.addRow(new Object[] { "a", "b" });
return tableModel;
}
private static TableModel createTableModel2() {
DefaultTableModel tableModel = new DefaultTableModel();
tableModel.setColumnCount(2);
tableModel.addRow(new Object[] { "c", "d" });
return tableModel;
}
private static void showFrame(JFrame frame) {
frame.setSize(240, 400);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
I've 2 panels. One where the user inserts the data and the other with a JTable where the results will be shown.
My problem is when the user press's the ok (in my case apply) JButton the data is computed but is not shown on the JTable, nothing changes in the JTable.
For my JTable I'm using the Bean Table Model from tips4Java (http://tips4java.wordpress.com/2008/11/27/bean-table-model/).
One weird thing is if I send data (lets call this data 'A') to the table when the program starts it is shown on the table and if later on I try to update the table, the table does not update. But when I don't send data to the table at start up but try to update/send the table with data 'A' it does not update.
So my question is, why is not the JTable showing whatever data I send to?
Here's my code:
JButton listenere that starts the processing and sends the data to the table:
crashForm.setFormListener(new FormListener() {
#Override
public void formEvent(OptionsFormEvent oe) {
String readTable = oe.getReadFromTable();
int access = oe.getAccess();
int transition = oe.getTransition();
boolean smooth = oe.isTrainCrash();
ArrayList<String> allTrains = new ArrayList<>();
List crashedTrainList = new ArrayList<>();
try {
allTrains = controller.getUniqueTrains(controller.connectServer(), readTable, "trainid");
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, "An error occured while getting trains data\n"
+ "Error description: " + ex.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
}
try {
for (int i = 0; i < allTrains.size(); i++)
{
ArrayList<Train> trainDataList = new ArrayList<>();
ArrayList<Train> crashedProccessedData = new ArrayList<>();
String query = "the sql query...";
trainDataList = controller.getTrainData(controller.connectServer(), readTable, query);
crashedProccessedData = controller.detectCrash(access, transition, trainDataList);
crashedTrainList.addAll(crashedProccessedData);
}
} catch (Exception ex) {
JOptionPane.showMessageDialog(null, "An error occured while detecting a crash.\n"
+ "Error description: " + ex.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
}
System.out.println("Total crashes detected:" + crashedTrainList.size());
tablePanel.createTable(Train.class, crashedTrainList, true, false, tableLabels);
tablePanel.fireTableDataChanged();
}
});
}
And here's my tablePanel class:
public TablePanel() {
}
public void createTable(Class c, List data, boolean toolBarUp,
boolean toolBarBottom, ArrayList<String> labelsCheckBox) {
beanTableModel = new BeanTableModel(c, data);
columnModel = new XTableColumnModel();
table = new JTable(beanTableModel);
table.setColumnModel(columnModel);
table.createDefaultColumnsFromModel();
if(toolBarUp == true)
{
final JToolBar toolBarTop = new JToolBar();
// Create the Show ALL
JButton reset = new JButton("Reset");
reset.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for(Component c : toolBarTop.getComponents()){
if(c instanceof JCheckBox){
JCheckBox checkBox = (JCheckBox) c;
checkBox.setSelected(false);
columnModel.setAllColumnsVisible();
}
}
int numberOfColumn = columnModel.getColumnCount();
for(int aux = 0; aux < numberOfColumn; aux++)
{
int num = columnModel.getColumnCount();
TableColumn column = columnModel.getColumnByModelIndex(aux);
columnModel.setColumnVisible(column, true);
}
}
});
toolBarTop.add(reset);
// Create a JCheckBox for each column
for(int i = 0; i < labelsCheckBox.size(); i++)
{
final int index = i;
toolBarTop.add(new JCheckBox(new AbstractAction(labelsCheckBox.get(i)) {
#Override
public void actionPerformed(ActionEvent e) {
TableColumn column = columnModel.getColumnByModelIndex(index);
boolean visible = columnModel.isColumnVisible(column);
columnModel.setColumnVisible(column, !visible);
}
}));
}
setLayout(new BorderLayout());
add(toolBarTop, BorderLayout.NORTH);
add(new JScrollPane(table), BorderLayout.CENTER);
// add(toolBarDown, BorderLayout.SOUTH);
}
final JToolBar toolBarDown = new JToolBar();
toolBarDown.add(new JButton(new AbstractAction("Save Table") {
#Override
public void actionPerformed(ActionEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
}));
}
public void createTable(Class c, Class cAncestor) {
beanTableModel = new BeanTableModel(c, cAncestor);
table = new JTable(beanTableModel);
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
}
public void createTable(Class c, Class cAncestor, List data) {
beanTableModel = new BeanTableModel(c, cAncestor, data);
table = new JTable(beanTableModel);
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
beanTableModel.fireTableDataChanged();
}
public void createTable(Class c) {
beanTableModel = new BeanTableModel(c);
table = new JTable(beanTableModel);
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
}
public void createTable(Class c, List data)
{
beanTableModel = new BeanTableModel(c, data);
table = new JTable(beanTableModel);
setLayout(new BorderLayout());
add(new JScrollPane(table), BorderLayout.CENTER);
}
//to refresh the table everytime there is an update
public void fireTableDataChanged()
{
beanTableModel.fireTableDataChanged();
}
So again, my question is: Isn't my JTable not updated with the new results every time I send new data to it?
You should never invoke fireTableDataChanged manually. Only the TableModel is responsible for invoking this event.
From your code it looks like you are creating a new TableModel, JTable and JScrollPane every time you make a change. Any time you add a component to a visible GUI the basic code should be:
panel.add(....);
panel.revalidate();
panel.repaint();
By default all components have a size of zero so since you don't invoke revalidate() then never get a proper size and there is nothing to paint. Also, it is never a good idea to simply keep adding components to the CENTER of your panel since the old component are still part of the container.
However, there is a better solution. There is no need to keep creating new components. All you need to do is create an new TableModel and then use:
table.setModel( newlyCreatedModel );
and the model will be added to the table and the table will repaint itself automatically.
I'm creating a program that reads data from a file, displays it on a GUI that has a JList and JButtons. I am trying to write it with CardLayout so the appropriate JPanel can be displayed when an item is selected from the JList or a JButton is clicked (i.e. next, previous, first and last). I am able to successfully read from the file and display data to the GUI. I've run into 2 problems and I've tried searching online for answers but cant seem to figure it out:
1) How do I get the JPanels to switch using CardLayout?
2) How do I get the data to be displayed in the GUI in text fields when a user clicks an item from the JList? The JList does appear and my ListSelectionListener is working because when I click on a particular item, it will print to the console (as a test).
If I comment out all of the JPanels except for 1, then it is correctly displayed but when I place all of them, then it does not switch.
So far, I have this for my ListSelectionListener (as an inner class):
public class CancerSelectionListener implements ListSelectionListener {
#Override
public void valueChanged(ListSelectionEvent e) {
Integer selection = (Integer)(((JList) e.getSource()).getSelectedIndex());
if(selection == 0) {
System.out.println("blah"); // works
// switch to the corresponding JPanel in CardLayout
}
}
}
String[] tester;
String teste;
listModel = new DefaultListModel();
for(int i = 0; i < 36; i++) {
tester = _controller.readCancer(i); // reads from the file, this part works!
teste = tester[0];
listModel.addElement(teste);
}
cancerList = new JList(listModel);
cancerList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
cancerList.setSelectedIndex(-1);
cancerList.setVisibleRowCount(5);
cancerListScroller = new JScrollPane(cancerList);
CardLayout myCardLayout;
myCardLayout = new CardLayout();
mainPanel2.setLayout(myCardLayout);
myCardLayout.show(mainPanel2, "test");
CancerPanels.aplPanel apl = new CancerPanels.aplPanel();
CancerPanels.fcPanels fc = new CancerPanels.fcPanels();
CancerPanels.vhlsPanels vhls = new CancerPanels.vhlsPanels();
CancerPanels.pdgPanels pdg = new CancerPanels.pdgPanels();
CancerPanels.cebpaPanels cebpa = new CancerPanels.cebpaPanels();
mainPanel2.add(apl.aplReturn(), "test");
mainPanel2.add(fc.fcReturn());
mainPanel2.add(vhls.vhlsReturn());
mainPanel2.add(pdg.pdgReturn());
mainPanel2.add(cebpa.cebpaReturn());
// I have 37 JPanels that are placed in the JPanel that uses CardLayout but I didn't post all of them as it would take up lots of space
The data for each JPanel is populated from static inner classes in the CancerPanels class (only showing 1 as each is very long!)
public class CancerPanels extends CancerGUI {
static JPanel cards;
static CancerController _cons = new CancerController();
static String[] cancerData;
static JScrollPane treatmentsScroller = new JScrollPane(txtTreatments, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
static JScrollPane causesScroller = new JScrollPane(txtCauses, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
static JScrollPane symptomsScroller = new JScrollPane(txtSymptoms, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
public static class aplPanel extends JPanel {
public JPanel aplReturn() {
treatmentsScroller.setViewportView(txtTreatments);
txtTreatments.setEditable(false);
causesScroller.setViewportView(txtCauses);
txtCauses.setEditable(false);
symptomsScroller.setViewportView(txtSymptoms);
txtSymptoms.setEditable(false);
cards = new JPanel(new GridLayout(6,1));
cancerData = _cons.readCancer(0);
resultName.setText(cancerData[0]);
txtSymptoms.setText(cancerData[1]);
txtCauses.setText(cancerData[2]);
txtTreatments.setText(cancerData[3]);
resultRate.setText(cancerData[4]);
resultPrognosis.setText(cancerData[5]);
cards.add(resultName);
cards.add(symptomsScroller);
cards.add(causesScroller);
cards.add(treatmentsScroller);
cards.add(resultRate);
cards.add(resultPrognosis);
return cards;
}
}
Edit:
Here is my most recent attempt. I can scroll through the JList but it doesn't properly display the correct corresponding JPanel (in fact it doesn't display anything, except whenever I click the last button, I don't know why that button works). I successfully managed to place an ItemListener on a JComboBox but ultimately, I want the CardLayout to work. Our instructor provided us with sample code to use but when I try it, the JPanels do not switch (or if they do they're hidden, not sure why).
Each of my listeners are public inner classes in the overall CancerGUI class.
public CancerGUI() {
CancerPanels.aplPanel apl = new CancerPanels.aplPanel();
CancerPanels.fcPanels fc = new CancerPanels.fcPanels();
CancerPanels.vhlsPanels vhls = new CancerPanels.vhlsPanels();
// more than 30 JPanels that I add to the JPanel that uses CardLayout, so I only posted 3
// each of them uses the GridLayout
mainPanel2 = new JPanel(new CardLayout());
mainPanel2.add(apl.aplReturn(), "1");
mainPanel2.add(fc.fcReturn(), "2");
mainPanel2.add(vhls.vhlsReturn(), "3");
CancerActionButtons _cab = new CancerActionButtons();
btnNext = new JButton("Next");
btnPrevious = new JButton("Previous");
btnFirst = new JButton("First");
btnLast = new JButton("Last");
btnClear = new JButton("Clear");
btnNext.addActionListener(_cab);
btnPrevious.addActionListener(_cab);
btnFirst.addActionListener(_cab);
btnLast.addActionListener(_cab);
CancerItemListener _item = new CancerItemListener(); // this listener works!
renalC.addItemListener(_item);
skinC.addItemListener(_item);
brainC.addItemListener(_item);
bladderC.addItemListener(_item);
ovarianC.addItemListener(_item);
pancC.addItemListener(_item);
breastC.addItemListener(_item);
String[] tester;
String teste;
listModel = new DefaultListModel();
for(int i = 0; i < 36; i++) {
tester = _controller.readCancer(i);
teste = tester[0];
listModel.addElement(teste);
}
cancerList = new JList(listModel);
cancerList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
cancerList.setSelectedIndex(-1);
cancerList.setVisibleRowCount(5);
cancerListScroller = new JScrollPane(cancerList);
ListSelection _list = new ListSelection();
cancerList.addListSelectionListener(_list);
JScrollPane treatmentsScroller = new JScrollPane(txtTreatments, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
treatmentsScroller.setViewportView(txtTreatments);
JScrollPane causesScroller = new JScrollPane(txtCauses, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
causesScroller.setViewportView(txtCauses);
JScrollPane symptomsScroller = new JScrollPane(txtSymptoms, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
symptomsScroller.setViewportView(txtSymptoms);
public class ListSelection implements ListSelectionListener {
#Override
public void valueChanged(ListSelectionEvent e) {
String selection = (String)(((JList)e.getSource()).getSelectedValue());
((CardLayout) mainPanel2.getLayout()).show(mainPanel2, selection);
((CardLayout) mainPanel2.getLayout()).show(mainPanel2, selection);
}
}
public class CancerActionButtons implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
switch(e.getActionCommand()) {
case "First":
((CardLayout) mainPanel2.getLayout()).first(mainPanel2);
cancerCount = 1;
break;
case "Last":
((CardLayout) mainPanel2.getLayout()).last(mainPanel2);
cancerCount = 11;
break;
case "Previous":
((CardLayout) mainPanel2.getLayout()).previous(mainPanel2);
cancerCount--;
cancerCount = cancerCount < 1 ? 11 : cancerCount;
break;
case "Next":
((CardLayout) mainPanel2.getLayout()).next(mainPanel2);
cancerCount++;
cancerCount = cancerCount > 11 ? 1 : cancerCount; //
break;
}
cancerList.setSelectedIndex(cancerCount-1);
}
}
/**
* Inner class that responds to any user interaction with a JComboBox for
* general types of cancers.
*/
public class CancerItemListener implements ItemListener {
#Override
public void itemStateChanged(ItemEvent e) {
JPanel showPanel = new JPanel();
if(e.getStateChange() == ItemEvent.SELECTED) {
String selection = (String) e.getItem();
if(selection.equalsIgnoreCase("skin cancer")) {
CancerPanels.skin skin = new CancerPanels.skin();
showPanel = skin.skinReturn();
} else if (selection.equalsIgnoreCase("bladder cancer")) {
CancerPanels.bladder bladder = new CancerPanels.bladder();
showPanel = bladder.bladderReturn();
} else if (selection.equalsIgnoreCase("pancreatic cancer")) {
CancerPanels.pancreatic pancreatic = new CancerPanels.pancreatic();
showPanel = pancreatic.returnPancreatic();
} else if (selection.equalsIgnoreCase("renal cancer")) {
CancerPanels.renal renal = new CancerPanels.renal();
showPanel = renal.returnRenal();
} else if (selection.equalsIgnoreCase("ovarian cancer")) {
CancerPanels.ovarian ovarian = new CancerPanels.ovarian();
showPanel = ovarian.ovarianReturn();
} else if (selection.equalsIgnoreCase("breast cancer")) {
CancerPanels.breast breast = new CancerPanels.breast();
showPanel = breast.returnBreast();
} else if (selection.equalsIgnoreCase("brain cancer")) {
CancerPanels.brain brain = new CancerPanels.brain();
showPanel = brain.returnBrain();
} else if (selection.equalsIgnoreCase("von hippel-lindau syndrome")) {
CancerPanels.vhlsPanels vhls = new CancerPanels.vhlsPanels();
showPanel = vhls.vhlsReturn();
}
JOptionPane.showMessageDialog(null, showPanel);
}
}
}
Seperate class where the JPanels are made before being added to CardLayout:
public class CancerPanels extends CancerGUI {
static String name;
static JPanel cards;
static CancerController _cons = new CancerController();
static String[] cancerData;
static JScrollPane treatmentsScroller = new JScrollPane(txtTreatments, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
static JScrollPane causesScroller = new JScrollPane(txtCauses, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
static JScrollPane symptomsScroller = new JScrollPane(txtSymptoms, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
public static class aplPanel extends JPanel {
public JPanel aplReturn() {
treatmentsScroller.setViewportView(txtTreatments);
txtTreatments.setEditable(false);
causesScroller.setViewportView(txtCauses);
txtCauses.setEditable(false);
symptomsScroller.setViewportView(txtSymptoms);
txtSymptoms.setEditable(false);
cards = new JPanel(new GridLayout(6,1));
cancerData = _cons.readCancer(0);
resultName.setText(cancerData[0]);
txtSymptoms.setText(cancerData[1]);
txtCauses.setText(cancerData[2]);
txtTreatments.setText(cancerData[3]);
resultRate.setText(cancerData[4]);
resultPrognosis.setText(cancerData[5]);
cards.add(resultName);
cards.add(symptomsScroller);
cards.add(causesScroller);
cards.add(treatmentsScroller);
cards.add(resultRate);
cards.add(resultPrognosis);
return cards;
}
In essence what you are trying to do is to change the state of one class from another.
How this is done with Swing GUI's is no different for how it is done for non-GUI programs: one class calls the public methods of another class.
One key is to have wiring to allow this to occur which means references for one class needs to be available to the other class so that appropriate methods can be called on appropriate references. The devil as they say is in the details.
"1) How do I get the JPanels to switch using CardLayout?" -- So the class that holds the CardLayout could for instance have the public methods, next(), previous(), and perhaps show(SOME_STRING_CONSTANT) or some other swapView(...) method.
"2) How do I get the data to be displayed in the GUI in text fields when a user clicks an item from the JList?" -- This will involve the use of listeners -- the class holding the JTextFields will listen for notification from the class that holds the JList, and when notified gets the necessary information from the list-displaying class. A PropertyChangeListener could work well here.
e.g.,
public class CancerSelectionListener implements ListSelectionListener {
private CardDisplayingView cardDisplayingView = null;
public CancerSelectionListener(CardDisplayingView cardDisplayingView) {
this.cardDisplayingView = cardDisplayingView;
}
#Override
public void valueChanged(ListSelectionEvent e) {
int selection = ((JList) e.getSource()).getSelectedIndex();
if(selection == 0) {
if (cardDisplayingView != null) {
cardDisplayingView.swapView(...);
}
}
}
}
I created a program to set an imageIcon in jtable fixed column, i created a jtable and getting a database records, then set a first column as fixed column. i set an image icon in fixed column. when i am compiling this program, i am getting only a path of the imageicon not getting an image. I fixed an imageIcon in project package folder.
This is the code i used
public void Frm_FlxD_Database() {
try{
TmpRow=0;
TmpMainPrj.PRJ_DB_CONNECTION_ASSGN();
TmpFlxMdl =(DefaultTableModel)FlxD.getModel();
TmpFlxDRow = 0;
TmpFlxSt=TmpGPrjVarDec.GContn.createStatement();
TmpFlxDRs=TmpFlxSt.executeQuery("SELECT * from activitymaster");
PRJ_FLX_DEFTL_ASSGN(FlxD, "BEGIN");
TmpFlxDRs.first();
do {
FlxD.setValueAt(TmpFlxDRs.getString("ACTVTYDESC"), TmpRow,1);
FlxD.setValueAt(TmpFlxDRs.getString("ACTVTYCODE"), TmpRow,2);
FlxD.setValueAt(TmpFlxDRs.getString("DISPSTATUS"), TmpRow,3);
FlxD.setValueAt(TmpFlxDRs.getString("ACTVTYID"), TmpRow,4);
TmpFlxMdl.addRow(new Object[]{""});
TmpRow = TmpRow + 1;
}while(TmpFlxDRs.next());
FRM_FLXD_PTR_DATA_ASSGN(TmpFlxDRow);
}
catch(Exception e){
System.out.println(e);
}
}
private void FRM_FLXD_PTR_DATA_ASSGN(int PFlxRow) {
TmpFlxDRow = PRJ_FLX_PTR_ASSGN(FlxD, PFlxRow, TmpFlxDRow);
}
private int PRJ_FLX_PTR_ASSGN(JTable PFlx, int PCurRow, int PPrvRow) {
ImageIcon TmpIcon;
System.out.println(PCurRow);
System.out.println(PPrvRow);
if (PCurRow != PPrvRow){
TmpIcon = new ImageIcon(getClass().getResource("Blank.gif"));
PFlx.setValueAt(TmpIcon,PPrvRow,0);
System.out.println(TmpIcon);
}
TmpIcon = new ImageIcon(getClass().getResource("Pointer.gif"));
PFlx.setValueAt(TmpIcon,PCurRow,0);
System.out.println(TmpIcon);
return(PCurRow);
}
JTable knows Icon/ImageIcon, simple example
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import javax.swing.*;
import javax.swing.table.*;
public class TableIcon extends JFrame implements Runnable {
private static final long serialVersionUID = 1L;
private JTable table;
private JLabel myLabel = new JLabel("waiting");
private int pHeight = 40;
private boolean runProcess = true;
private int count = 0;
public TableIcon() {
ImageIcon errorIcon = (ImageIcon) UIManager.getIcon("OptionPane.errorIcon");
ImageIcon infoIcon = (ImageIcon) UIManager.getIcon("OptionPane.informationIcon");
ImageIcon warnIcon = (ImageIcon) UIManager.getIcon("OptionPane.warningIcon");
String[] columnNames = {"Picture", "Description"};
Object[][] data = {{errorIcon, "About"}, {infoIcon, "Add"}, {warnIcon, "Copy"},};
DefaultTableModel model = new DefaultTableModel(data, columnNames);
table = new JTable(model) {
private static final long serialVersionUID = 1L;
// Returning the Class of each column will allow different
// renderers to be used based on Class
#Override
public Class getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
table.setRowHeight(pHeight);
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER);
myLabel.setPreferredSize(new Dimension(200, pHeight));
myLabel.setHorizontalAlignment(SwingConstants.CENTER);
add(myLabel, BorderLayout.SOUTH);
EventQueue.invokeLater(new Runnable() {
public void run() {
}
});
new Thread(this).start();
}
public void run() {
while (runProcess) {
try {
Thread.sleep(750);
} catch (Exception e) {
e.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ImageIcon myIcon = (ImageIcon) table.getModel().getValueAt(count, 0);
String lbl = "JTable Row at : " + count;
myLabel.setIcon(myIcon);
myLabel.setText(lbl);
count++;
if (count > 2) {
count = 0;
}
}
});
}
}
public static void main(String[] args) {
TableIcon frame = new TableIcon();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setLocation(150, 150);
frame.pack();
frame.setVisible(true);
}
}
You should not add an icon in your data model. You should add data (a boolean indicator, a String, whatever), and use a renderer for this column that will display the appropriate icon based on the data of the column.
See http://docs.oracle.com/javase/tutorial/uiswing/components/table.html#editrender for information and examples about cell renderers.
And please, learn the Java naming conventions and stick to them. Your code is unreadable. See http://www.oracle.com/technetwork/java/codeconv-138413.html
Without getting to much into your code my guess is it has something to do with your tablemodel getColumnClass() method. There are plenty of tutorials how to fix that. Currently its probably rendered by tables defaultrenderer for object.
This thread should be helpful to you.
Good news is, you dont have to obfuscate your code, its already really hard to read and even harder to understand. You might want to read some java code guidelines to improve your code.