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.
Related
Newbie seeking help please :-)
I am working on a little project to get familiar with Java desktop development and Database connectivity.
Attached code gives me an empty TableModel after instantiating therefore no data displayed in the JFrame.
Test class is instantiated from the menue of the main window with Test.showFrame();.
package ...
import ...
public class Test extends JPanel {
public Test() {
initializePanel();
}
private void initializePanel() {
// Creates an instance of TableModel
CategoryTableModel tableModel = new CategoryTableModel();
System.out.println(tableModel.getRowCount());
// Creates an instance of JTable with a TableModel
// as the constructor parameters.
JTable table = new JTable(tableModel);
table.setFillsViewportHeight(true);
JScrollPane scrollPane = new JScrollPane(table);
this.setPreferredSize(new Dimension(500, 200));
this.setLayout(new BorderLayout());
this.add(scrollPane, BorderLayout.CENTER);
}
public static void showFrame() {
JPanel panel = new Test();
panel.setOpaque(true);
JFrame frame = new JFrame("test");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
}
class CategoryTableModel extends AbstractTableModel {
private List<Category> all = null;
private Iterator<Category> iterator = null;
private int tableRowCount;
private TableModel tableModel;
public CategoryTableModel(){
Vector tableData = new Vector();
// TableModel's column names
Vector<String> tableHeaders = new Vector<String>();
tableHeaders.add("Category");
// Database call
all = new ReadCategory().allCategories();
// TableModel's data
for(Object o : all) {
Vector<Object> row = new Vector<Object>();
all.forEach((n) -> row.add(new Category().getName()));
tableData.add(row);
System.out.println("row added");
}
tableRowCount = tableData.size();
tableModel = new DefaultTableModel(tableData, tableHeaders);
System.out.println(tableModel.getRowCount());
}
#Override
public int getRowCount() {
return 0;
}
#Override
public int getColumnCount() {
return 0;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
return null;
}
}
}
Database call is fetching data via Hibernate and stores data in a .
Thanks for help.
In its most basic form a table model for a JTable defines the columns, the mapping of object to column and holds the data for the JTable to call upon. If we take your current table model and cut it down to fit this basic requirement we get the following.
import java.util.ArrayList;
import java.util.List;
import javax.swing.table.AbstractTableModel;
public class CategoryTableModel extends AbstractTableModel {
private final List<Category> tableData = new ArrayList<>();
public void add(Category cat) {
tableData.add(cat);
fireTableDataChanged();
}
#Override
public String getColumnName(int column) {
String result = "";
if (column == 0) {
result = "Category Name";
}
return result;
}
#Override
public int getRowCount() {
return tableData.size();
}
#Override
public int getColumnCount() {
return 1;
}
#Override
public Object getValueAt(int rowIndex, int columnIndex) {
if (columnIndex == 0) {
return tableData.get(rowIndex).getName();
}
return null;
}
}
Notice that we do not define any data in the model itself. All we define is some storage for the data and the column name of the single column that we require.
I have added an add() method that allows you to add data to the model (you may wish to define remove etc. yourself). When you add or remove data from the model you must always let the JTable know that the data has changed by calling fireTableDataChanged() so that the table can redraw itself.
To use this table model you will need to do
CategoryTableModel model = new CategoryTableModel();
model.add(new Category());
JTable table = new JTable(model);
You can replace the model.add() with a loop that iterates over your data and adds it to the model.
I am trying to add a button inside a table cell. I am using the drag and drop method of netbeans since I know nothing about coding and will appreciate if you can teach me to code it. Thanks!
If you are using drag&drop in netbean for swing,
I highly advise you to touch the fundamental of swings , get your hands dirty so that you will know what is going on and how does the code work.
let me run through how you can achieve this. it will consist of 3 classes so that you will have a better understanding on what is going on and it practices oop too but of cause you can modify it to your preferred design pattern.
_main.java
public class _main extends JFrame{
private static final long serialVersionUID = 1L;
// Create new JFrame
_main(){
new JFrame("Main");
setLayout(new BorderLayout());
setSize(500,300);
add(new JLabel("Table Example ", SwingUtilities.CENTER) , BorderLayout.PAGE_START);
// ---------------- Call the method you have created in tableView.java ------------
add(new JScrollPane(new tableView(this).sampleTable()), BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args){
//Run Program
new _main();
}
}
tableView.java
public class tableView {
JFrame frame = new JFrame();
public tableView(JFrame frame) {
this.frame = frame;
}
//Create columnTitle & Table Model
String[] columnTitle = { "Data 1", "Data 2", "Data 3", "Buttons " };
DefaultTableModel model = new DefaultTableModel(columnTitle, 0);
public JTable sampleTable(){
JTable _dataTable = new JTable(model) {
#Override
public void updateUI() {
super.updateUI();
setRowHeight(34);
setAutoCreateRowSorter(true);
//------------ Placing button at your desired column ------------
TableColumn column;
column = getColumnModel().getColumn(3);
column.setCellRenderer(new tableModel(frame).new viewRenderer());
column.setCellEditor(new tableModel(frame).new ButtonsEditorView(this));
}
};
DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
centerRenderer.setHorizontalAlignment(JLabel.CENTER);
//-------- Adding data to your table row , use for loop for multiple data ---------
model.addRow(new Object[]{"1","2","3"});
return _dataTable;
}
}
tableModel.java
public class tableModel extends tableView{
public tableModel(JFrame frame) {
super(frame);
}
class viewButton extends JPanel {
public JButton viewbtnp = new JButton("View");
protected viewButton() {
setOpaque(true);
setFocusable(false);
add(viewbtnp);
}
}
class viewRenderer implements TableCellRenderer {
private final viewButton panel = new viewButton() {
#Override
public void updateUI() {
super.updateUI();
setName("Table.cellRenderer");
}
};
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
panel.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
return panel;
}
}
class ViewAction extends AbstractAction {
private final JTable table;
protected ViewAction(JTable table) {
super("view");
this.table = table;
}
#Override
public void actionPerformed(ActionEvent e) {
//--------------------------- Create your own function on what you want the button to do when button is clicked -------------
System.out.println("Clicked ");
}
}
class ButtonsEditorView extends AbstractCellEditor implements TableCellEditor {
protected final viewButton panel = new viewButton();
protected final JTable table;
protected ButtonsEditorView(JTable table) {
super();
this.table = table;
panel.viewbtnp.setAction(new ViewAction(table));
}
#Override
public Component getTableCellEditorComponent(JTable tbl, Object value, boolean isSelected, int row,
int column) {
panel.setBackground(tbl.getSelectionBackground());
return panel;
}
#Override
public Object getCellEditorValue() {
return "";
}
}
}
Output
Hope it helps.
Cheers
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.
I need to create a JTable inside JScrollPane with resizeable columns (when user increase column width - horizontal scrollbar appears).
For this I have use table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);.
Also, when viewport is wide enough to contain entire table - columns should stretch to fill viewport width.
To accomplish this I have override getScrollableTracksViewportWidth() method of JTable class as follow:
#Override
public boolean getScrollableTracksViewportWidth() {
return getPreferredSize().width < getParent().getWidth();
}
This approach works good, except one thing: when I first time try to resize column it return own width to start position. If I quickly resize column and release mouse table continue to work good.
So, what is the reason of such behavior? Why table try to resize even if getScrollableTracksViewportWidth() returns false? Or, maybe, you can propose better solution for implementing such resize mode?
Bellow is a simple working example of above problem:
import javax.swing.*;
public class TestTable {
private static Object[][] data = new Object[][] {
{ "a", "b", "c" },
{ "d", "e", "f" }
};
private static Object[] colNames = new Object[] { "1", "2", "3" };
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JTable table = new JTable(data, colNames) {
#Override
public boolean getScrollableTracksViewportWidth() {
return getPreferredSize().width < getParent().getWidth();
}
};
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(table));
frame.pack();
frame.setVisible(true);
}
});
}
}
It seemed like the default doLayout() logic wasn't working when you tried to increase the size of a column when the horizontal scrollbar wasn't visible, so I got rid of the default logic and just accepted the width of the column without attempting to adjust it.
import javax.swing.*;
import javax.swing.table.*;
public class TestTable {
private static Object[][] data = new Object[][] {
{ "a", "b", "c" },
{ "d", "e", "f" }
};
private static Object[] colNames = new Object[] { "1", "2", "3" };
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JTable table = new JTable(data, colNames)
{
#Override
public boolean getScrollableTracksViewportWidth()
{
return getPreferredSize().width < getParent().getWidth();
}
#Override
public void doLayout()
{
TableColumn resizingColumn = null;
if (tableHeader != null)
resizingColumn = tableHeader.getResizingColumn();
// Viewport size changed. May need to increase columns widths
if (resizingColumn == null)
{
setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
super.doLayout();
}
// Specific column resized. Reset preferred widths
else
{
TableColumnModel tcm = getColumnModel();
for (int i = 0; i < tcm.getColumnCount(); i++)
{
TableColumn tc = tcm.getColumn(i);
tc.setPreferredWidth( tc.getWidth() );
}
// Columns don't fill the viewport, invoke default layout
if (tcm.getTotalColumnWidth() < getParent().getWidth())
setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
super.doLayout();
}
setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
}
};
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(table));
frame.pack();
frame.setVisible(true);
}
});
}
}
Edited to use AUTO_RESIZE_ALL_COLUMNS.
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.