Here is the code for a java applet in which, the combobox will retrieve content from access database and while we select an item it must display the rows of the table which have the 'composition' field as the selected combobox item. My problem is, this works fine for the first time I select it. While the result of my first selection is being shown(which is a table), if I make a second selection on the combo box, the panel becomes blank. I want it to repeatedly show corresponding outputs for successive selections also. Kindly help me diagnose the error. Thanks in advance!
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
import java.util.Date;
import java.sql.*;
import java.text.*;
public class gc implements ActionListener
{
JComboBox cc=new JComboBox();
JFrame frame=new JFrame();
JTable table;
DefaultTableModel model;
String query;
int i;
JPanel panel=new JPanel();
public gc()
{
frame.setTitle("Composition Check");
frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
JPanel p1=new JPanel();
p1.setLayout(new FlowLayout());
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection conn=DriverManager.getConnection("jdbc:odbc:vasantham","","");
Statement st=conn.createStatement();
ResultSet rs=st.executeQuery("select DISTINCT composition from try");
while(rs.next())
{
cc.addItem(rs.getString("composition"));
}
conn.close();
}
catch(Exception e)
{
}
p1.add(cc);
cc.addActionListener(this);
frame.add(p1,BorderLayout.NORTH);
frame.setVisible(true);
}
public void addTable(String query)
{
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection conn=DriverManager.getConnection("jdbc:odbc:vasantham","","");
Statement st=conn.createStatement();
System.out.println(query);
ResultSet rs=st.executeQuery(query);
ResultSetMetaData md=rs.getMetaData();
int cols=md.getColumnCount();
model=new DefaultTableModel();
model.addColumn("Purpose");
model.addColumn("Name");
model.addColumn("Manu");
model.addColumn("Expiry");
model.addColumn("Stock");
model.addColumn("Cost");
model.addColumn("Supplier");
model.addColumn("Supplier Number");
model.addColumn("Rack");
table=new JTable(model);
String[] tabledata=new String[cols];
int i=0;
while(rs.next())
{
for(i=0;i<cols;i++)
{
tabledata[i]=rs.getObject(i+1).toString();
}
model.addRow(tabledata);
}
JScrollPane scroll = new JScrollPane(table);
panel.setLayout(new BorderLayout());
panel.add(scroll,BorderLayout.CENTER);
frame.add(panel,BorderLayout.CENTER);
conn.close();
}
catch(Exception e)
{
}
}
public void actionPerformed(ActionEvent evt)
{
String ac=(String)cc.getSelectedItem();
System.out.println(ac);
addTable("select * from try where composition='"+ac+"'");
frame.setVisible(true);
}
public static void main(String[] args)
{
new gc();
}
}
Add
panel.removeAll();
Before you add the scroll pane. This will clear the pane and make room for the next set of results...
Update
It occues to me that a better approach would be to simple replace the table's model. This lessens the risk for memory leaks, by replacing the scroll pane & table on each run.
Add a class level reference to the JTable & in your ui unit code add
table = new JTable();
JScrollPane scroll = new JScrollPane(table);
panel.setLayout(new BorderLayout());
panel.add(scroll,BorderLayout.CENTER);
frame.add(panel,BorderLayout.CENTER);
Now, in your data update code, create the new model as your are and then call
table.setModel(model);
This should be faster to update, but more importantly, takes less memory to accomplish.
As for the date format. You have two choices. You can either format the value as it comes out if the database OR you can supply you own cell renderer.
public class SQLDateTableCellRenderer extends DefauktTableCellRenderer {
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
if (value instanceof java.sql.Date) {
value = new SimpleDateFormat("dd/MM/yyyy").format(value);
}
retrun super.getTableCellRenderer(...);
}
}
Forgive the short hand, I'm on my iPad. It would be better to use a static or class reference to the date format, but that would require meto type more ;)
You could then set this as the default renderer on the JTable. This saves you the need to know which columns need a SQL date formatted.
table.setDefaultRenderer(java.sql.Date, new SQLDateTableCellRenderer());
This, of course, means tat rather then converting the objects to strings when you extract them from the database, you will simply want to extract the objects directly
tabledata[i]=rs.getObject(i+1);
Make sure you convert the tabledata to a Object[] array instead of Strings.
Related
I am new to making GUIs and Java Swing and I'm trying to make a GUI which displays a table from a SQL database. The table is displayed using a JScrollPane. At first I thought that my other components (JLabel and JTextField) weren't being added to the content pane but they actually were they were just hidden underneath the ScrollPane. After reducing the ScrollPane's dimensions, now these other components show up but they are unable to be positioned with the setBounds method and always appear in the same place so that the last component added covers up the other ones entirely. As well as the code I've also included a screenshot of what the GUI looks like.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
public class LibraryAppGUI extends JFrame {
String sql;
String DB_PATH = LibraryAppGUI.class.getResource("LibraryManagement3.sqlite").getFile();
private JTable table;
private String columns[] = {"PatronFirstName", "PatronLastName"};
private TableModelListener tableModelListener;
public LibraryAppGUI () {
DefaultTableModel model = new DefaultTableModel(columns, 0);
table = new JTable(model);
try{populateSQL(table);} catch(Exception e1) {e1.printStackTrace();}
table.setCellSelectionEnabled(true);
table.setPreferredScrollableViewportSize(new Dimension(600, 300));
table.setFillsViewportHeight(false);
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setVisible(true);
getContentPane().add(scrollPane, BorderLayout.PAGE_START);
}
public void createSQL() throws ClassNotFoundException, SQLException {
Class.forName("org.sqlite.jdbc");
Connection connection = DriverManager.getConnection("jdbc:sqlite:" + DB_PATH);
PreparedStatement stmt = connection.prepareStatement("");
}
public void populateSQL(JTable table) throws ClassNotFoundException, SQLException {
sql = "select PatronFirstName, PatronLastName\r\n" +
"FROM Patron\r\n";
Class.forName("org.sqlite.JDBC");
Connection connection = DriverManager.getConnection("jdbc:sqlite:" + DB_PATH);
PreparedStatement stmt = connection.prepareStatement(sql);
ResultSet res = stmt.executeQuery();
while(res.next()) {
Object[] row = new Object[columns.length];
for (int i = 1; i <= columns.length; i++) {
row[i-1] = res.getObject(i);
}
((DefaultTableModel) table.getModel()).insertRow(res.getRow()-1, row);
}
res.close();
connection.close();
}
public static void main(String[] args) {
LibraryAppGUI window = new LibraryAppGUI();
//label to prompt user
JLabel welcome = new JLabel("Welcome to the library. Choose your patron: ");
welcome.setBounds(50,50, 100, 30);
window.getContentPane().add(welcome);
JTextField user = new JTextField("Enter the full name in this box.");
user.setBounds(150,150,100,30);
window.getContentPane().add(user);
window.setDefaultCloseOperation(EXIT_ON_CLOSE);
window.pack();
window.setLocationRelativeTo(null);
window.setVisible(true);
}
}
Why do you create your Swing components in two different places?
Don't create components in the main() method.
The label, text field and table should all created and added to the frame in the constructor, the same way you create and add the scrollpane/table.
In your code below:
JLabel welcome = new JLabel("Welcome to the library. Choose your patron: ");
welcome.setBounds(50,50, 100, 30);
window.getContentPane().add(welcome);
JTextField user = new JTextField("Enter the full name in this box.");
user.setBounds(150,150,100,30);
window.getContentPane().add(user);
The setBounds(...) statements should NOT be used. By default the content pane of the frame uses a BorderLayout. The layout manager will set the size/location of the components based on the rules of the layout manager.
When you don't specify a constraint when you add the components, then the BorderLayout.CENTER is used. However you can only add one component to the CENTER, so only the text field is given the proper size/location. The label is ignored.
So, assuming you move the GUI code from the main() method to the constructor, the proper design would be to do something like:
JPanel top = new JPanel();
top.add(welcome);
top.add(user);
add(top, BorderLayot.PAGE_START);
then you would also use:
//getContentPane().add(scrollPane, BorderLayout.PAGE_START);
add(scrollPane, BorderLayout.CENTER);
This will now display the lable and text field at the top of the frame and the scrollpane in the center. The scrollbars will then automatically adjust as the frame size is changed.
2015.5.5 22:11 updated. I found that, when I create a sorter and call setRowSorter() method in the MyTable's construction, afterwards, it
will keep the original line number(in which the data still refresh
correctly but not easy to discover)even though the dataModel inside is
already changed many times which can be proven as
printf(getModel().getRowCount()). What's more,
MyTable.getAutoCreateRowSorter() always return true. I must explicitly
call setAutoCreateRowSorter(true) to fix the issue it if I called
setRowSorter(). I am happy but this is still wierd.
[2015.5.5 6:19 updated] I have found a way to access: make a "setRow" with the combination of insertRow() and removeRow() and everytime I
update, I setrRow all the rows in the table. It reflect immediately in
the UI. BUT there will be a series of error begin with "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Invalid index" and I guess it's about some kiind of swing thread problem because I can see "RepaintManager" or "paint" in the error. It occurs especially when I move the scrollbar when it's running.(but it still occur if I don't move it)
I have a JTable in a JScrollPane in a JFrame. I initial a MyTableModel with a data and use it to Create a JTable.Like this
MyTableModel extends DefaultTableModel{
Data data;
//object
MyTableModel (Data a){
data = a;
// do something to initial the table model,like build object[][] and add rows.
}
}
class main{
MyTableModel tm = new MyTableModel(data);
Jtable table = new JTable(tm);
JScrollpane jsp = new JScrollpane(table);
JFrame window = new JFrame();
window.getxxxpane().add(jsp);
}
So, as my data is always changing/updating and the changed row is plural and impossible to caculate.
while(true){
data.change();
refreshing the table to display the data immediately;
}
my idea is to simply build a new MyTableModel object and set it as the table's model like:
table.setModel(new MyTableModel(data)); //data had been changed.
which doesn't work.
and I tried this:
tm = MyTableModel(data);
tm.fireTableDataChanged();
which doesn't work either.
and the combination as well:
MyTableModol nm = new MyTableModel(data); //data had been changed
table.setModel(nm);
nm.fireTableDataChanged();
Could someone please give me some clue to change the TableModel object in an unchangable Jtable and update everytime.I dont want to change the tableModel Object because the calculation is huge, instead ,i Want to always create a new object with the construction method's parameter(changed data).
the most worst method is to remove the JScrollpane and rebuild one table/tablemodel/jscrollpane and re-add it, in which I have to call window.setVisible(true). window.repait() doesn't work,either,unless I move it.
I create a space-wasting but runnable program for demostration ,which most of them are nonsense.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Formatter;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
class TM extends DefaultTableModel {
int[] inside;
static String[] columnNames = { "Hellium", "Radon",
};
TM(int[] data) {
super(columnNames, 0);
this.inside = data;
update();
}
void update() {
Object[][] data = new Object[2][columnNames.length];
for (int i = 0; i < 2; ++i) {
data[i][0] = inside[0];
data[i][1] = inside[1];
// setValueAt(aValue, row, column);
addRow(data[i]);
}
fireTableDataChanged();
}
}
class idkName {
TM tm;
JButton jb, jb2;
int data[] = { 1, 2 };
int data2[] = { 9, 10 };
JTable table;
JScrollPane jsp;
JFrame twindow;
idkName() {
JFrame window = new JFrame();
window.setSize(400, 400);
window.setLayout(new BorderLayout());
jb = new JButton("show");
jb2 = new JButton("change model");
window.add(jb, BorderLayout.EAST);
window.add(jb2, BorderLayout.WEST);
twindow = new JFrame();
jb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
tm = new TM(data);
table = new JTable(tm);
jsp = new JScrollPane(table);
twindow.getContentPane().add(jsp);
twindow.setSize(500, 500);
twindow.setVisible(true);
}
});
window.setVisible(true);
jb2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
// tm = new TM(data2);
tm = new TM(data2);
System.out.println(""+tm.getValueAt(0,0));
tm.fireTableDataChanged();
twindow.setVisible(true);
}
});
}
}
public class main2 {
TM tm;
public static void main(String[] args) {
idkName i = new idkName();
}
}
If you're going to extend DefaultTableModel, then when the data is changed, you need to update it in DefaultTableModel's internal representation using the setValueAt or setDataVector methods. If you have extensive changes (which it sounds like you do), use the setDataVector method to change all the cells and the table structure at once. Your example code looks like it's missing some updates because it's not pushing the new values in to the DefaultTableModel's data vectors.
But since you have a lot of updates, you're probably better off avoiding DefaultTableModel and just extending AbstractTableModel, using your own custom data storage, and calling the appropriate fireXxx() methods whenever your data changes. This will probably be more efficient in terms of both data conversion and number of events raised.
And then make sure all the event and value change work is done on the AWT event thread, using SwingWorkers or other threading support.
Why is there an A on the top of the table?
I placed a JTable inside a JScrollPane to make it scrollable.
Are there methods that I need to place?
I did not place a letter A though so I cant track.
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.BoxLayout;
import javax.swing.JTable;
import javax.swing.border.LineBorder;
import java.awt.Color;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
public class Rawr {
private JFrame frame;
private JScrollPane scrollPane;
private JTable table;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Rawr window = new Rawr();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Rawr() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.CENTER);
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
scrollPane = new JScrollPane();
scrollPane.setToolTipText("");
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
panel.add(scrollPane);
table = new JTable(100, 1);
table.setBorder(new LineBorder(new Color(0, 0, 0)));
scrollPane.setViewportView(table);
}
}
How do I remove it? Thanks!
Set the column name explicitly using:
String[] colNames = new String[]{"Your Column Name"};
DefaultTableModel defaultTableModel = new DefaultTableModel(colNames, 100);
table = new JTable(defaultTableModel);
If you create a table using new JTable(100, 1) you will see the A, B and so on column headers because the constructor javadoc says:
Constructs a JTable with numRows and numColumns of empty cells using DefaultTableModel.
Since the JTable constructor does not have any information about the column headers. It can only create a DefaultTableModel that does not know any column header names.
The DefaultTableModel extends AbstractTableModel and the javadoc of AbstractTableModel.getColumnName() says
Returns a default name for the column using spreadsheet conventions: A, B, C, ... Z, AA, AB, etc. If column cannot be found, returns an empty string.
Add the following code after the creation of your table.
String[] columns = new String[]{"Column Name"};
((DefaultTableModel)table.getModel()).setColumnIdentifiers(columns);
How do I remove it?
A JTable is designed to display data with a header to describe the data in the column.
Since you only have a single column of data, if you don't want the header then don't use a JTable. Instead you can use a JList.
Read the section from the Swing tutorial on How to Use Lists for more information and examples.
My code is working when I directly use jtable, but when I bound it with scroll panel, it runs one time. After another click on button it hides the data. Here is the code:
import java.awt.ScrollPane;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import com.mysql.jdbc.Statement;
class Scrl extends JFrame implements ActionListener
{
JScrollPane sp;
Icon back,front;
JLabel l,l1;
JTable tb=new JTable();
DefaultTableModel model;
String column[]={"JobcardNo","Customer Name","Brand","Date","PhoneNo"};
JTextField jobt=new JTextField("");
JButton b=new JButton("click");
public Scrl()
{
b.setBounds(200,140,100,20);
jobt.setBounds(114,50,100,20);
model = new DefaultTableModel();
tb.setModel(model);
model.setColumnIdentifiers(column);
add(jobt);
add(b);
b.addActionListener(this);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setResizable(false);
setLocationRelativeTo(null);
setLayout(null);
setSize(700,600);
setVisible(true);
setLocationRelativeTo(null);
}
#Override
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==b)
{
String job_no=jobt.getText();
try
{
Class.forName("com.mysql.jdbc.Driver");
Connection con=DriverManager.getConnection("jdbc:mysql://localhost:3306/ac_data","root","root");
java.sql.Statement st=con.createStatement();
ResultSet rs=st.executeQuery("select * from main");
while(rs.next())
{
String hey=rs.getString(1);
if(hey.equals(job_no))
{
System.out.println(rs.getString(2));
String jobno=rs.getString(1);
String names=rs.getString(2);
String brand=rs.getString(21);
String date=rs.getString(6);
String phoneno=rs.getString(4);
model.addRow(new Object[]{jobno,names,brand,date,phoneno});
}
}
}
catch(Exception ee)
{
}
}
JScrollPane sp=new JScrollPane(tb);
sp.setBounds(1,165,687,440);
add(sp);
}
public static void main(String[] args)
{
new Scrl();
}
}
Scroll panel is not refreshing data itslef.
You don't close the Connection when you're finished.
You should read the information from your database once, before you construct the GUI, and put the information into a TableModel.
You're trying to place all of the Swing components by hand when you should be using a layout manager.
You're not putting your Swing components on the Event Dispatch thread.
That should be enough reading and studying to keep you busy for a while.
The reason why it's not showing is that you're instantiating a new JScrollPane every single time your click the button. Instead, you should only instantiate it once somewhere it won't be re-created every time (ie: in your constructor).
Move the following to the end of your constructor:
JScrollPane sp=new JScrollPane(tb);
sp.setBounds(1,165,687,440);
Also, do not leave your catch exception empty because you will never know if your program is throwing an exception or not. Add the following to the catch exception clause:
ee.printStackTrace();
and deal with any errors that it prints out.
for school I am working on a Java GUI program to store some administrative data.
Now I want to display eventdata from my DB (mysql) into a JPanel with use of a JTextField,
my problem is I can't get the size of the JTextField fixed as it always takes up a lot of place (see picture)
Picture: http://postimg.org/image/5pcklo5n1/
Here's my code, anyone some tips? (I am new to java):
public void editEvent() {
JFrame frEventEdit = new JFrame ("Event Edit Menu");
frEventEdit.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frEventEdit.setVisible(true);
frEventEdit.setSize(700, 500);
//JPanel for displaying data
JPanel pnData = new JPanel();
pnData.setLayout(new BoxLayout(pnData, BoxLayout.PAGE_AXIS));
pnData.add(Box.createRigidArea(new Dimension(0,5)));
pnData.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
pnData.setAutoscrolls(true);
Statement stmt;
try {
stmt = mySql.createStatement();
ResultSet rs = stmt.executeQuery("SELECT name, date, time, type, address, representative FROM events " ) ;
while (rs.next() == true){
System.out.println(rs.getString("name")+" "+rs.getString("date")+" "+rs.getString("time")+" "+rs.getString("type")+" "+rs.getString("address")+" "+rs.getString("representative"));
final JTextField txtEventList = new JTextField(rs.getString("name")+" "+rs.getString("date")+" "+rs.getString("time")+" "+rs.getString("type")+" "+rs.getString("address")+" "+rs.getString("representative"));
pnData.add(txtEventList, BorderLayout.CENTER);
}
} catch (SQLException e) {
e.printStackTrace();
}
JScrollPane scroller = new JScrollPane(pnData);
frEventEdit.add(scroller);
frEventEdit.setLocationRelativeTo(null);
}
Thanks in advance
It happens because you use BoxLayout,try to use FlowLayout which is default for JPanel or another.
In next statement pnData.add(txtEventList, BorderLayout.CENTER); , BorderLayout.CENTER doesn't work, because you doesn't use BorderLayout for your panel.
For fixing size of JTextField, use constructor JTextField(int cols).
For your purposes use JTable as recommended by #AndrewThompson. Tutorial for table.
call frEventEdit.setVisible(true); at the end of construction or like next:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
frEventEdit.setVisible(true);
}
});