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.
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.
I'm trying to update a JFrame, and all of the components in the frame, including JPanel, JLabel components, etc. I tried using revalidate(), but that didn't seem to be working. I have a JLabel in the frame displaying an int, and I have the int iterating by 1 when I click a JButton. I can see that the value of the int changes, but the actual text on the label doesn't change. I know I can use JLabel.setText(), but is there a method to use for all components, that would update the displayed text/image upon pressing a button?
Here is my code below:
package repainttest;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Window extends JFrame {
int test = 1;
JLabel label;
public Window() {
setLayout(new FlowLayout());
label = new JLabel(Integer.toString(test));
add(label);
JButton button = new JButton("Add");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
test +=1;
System.out.println(test);
refresh();
}
});
add(button);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void refresh() {
SwingUtilities.updateComponentTreeUI(this);
revalidate();
repaint();
}
}
If you do not set the new text (test) on the JLabel, it is never going to know that the value of test is changing. So, please insert following statement:
label.setText(String.valueOf(test));
in public void actionPerformed(ActionEvent e) after following statement:
test +=1;
and see the results.
I have Jtable that I want to add to the main JFrame when a MenuItem is triggered, but the problem is that will not show.
If I add the table to panel from the beginning it shows, but I need it to show when the action occures.
Here is the main class that creates the frame(I removed several items which are not needed to be posted like creating the menubar,menu etc):
package gestiune;
import java.awt.event.ActionEvent;
import javax.swing.*;
import java.awt.*;
public class Gestiune {
static Gest gest;
static Action actListaAng;
static JPanel panouPrinc;
static ListaAngajati lang;
static JMenuItem listaAng;
static class Gest extends JFrame{
public Gest(){
actListaAng = new ActListaAng("List");
listaAng=new JMenuItem(actListaAng);
panouPrinc = new JPanel();
panouPrinc.setBackground(Color.white);
Container cp = getContentPane();
cp.add(panouPrinc);
pack();
setTitle("Some title");
setSize(1000,700);
setLocation(0,0);
setVisible(true);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}
}
public static void main(String[] args) {
gest = new Gest();
}
//class for listing action
static class ActListaAng extends AbstractAction {
public ActListaAng(String text){
super(text);
}
#Override
public void actionPerformed(ActionEvent e) {
lang = new ListaAngajati();
panouPrinc.add(lang);
}
}
}
Here is the table class:
package gestiune;
import javax.swing.*;
import java.awt.*;
public class ListaAngajati extends JPanel {
JTable tabel;
JScrollPane panouScroll;
public ListaAngajati() {
panouScroll = new JScrollPane(tabel);
String[] numeCol = {
"Nume",
"Prenume",
"Categorie",
"Data Adaugare",
"Ultima Modificare"
};
Object[][] linii = {
{"verban","adrian","sds","16-03-1989","acum"}
};
tabel = new JTable(linii,numeCol);
setLayout(new BorderLayout());
add(tabel.getTableHeader(), BorderLayout.PAGE_START);
add(panouScroll);
add(tabel);
}
}
I've tried several things, like using repaint on ActionEvent, or directly into the the table class......and while if I add lang=new ListaAngajati(); panouPrinc.add(lang); directly into the main jframe constructor works, from action it doesn't, so I kind of run out of options, so can someone give me a hand?
If you revalidate() and repaint() it works. You should always revalidate() and repaint() after adding a component during runtime.
#Override
public void actionPerformed(ActionEvent e){
lang=new ListaAngajati();
panouPrinc.add(lang);
panouPrinc.revalidate();
panouPrinc.repaint();
}
Also there was no button to click on, so I added a button here, and added the Action
Container cp=getContentPane();
JButton button = new JButton(new ActListaAng("Action"));
button.setText("Open");
cp.add(button, BorderLayout.PAGE_START);
cp.add(panouPrinc);
pack();
Works fine.
As a side note, you really need go through a tutorial on static. You're totally overly and unnecessarily using it.
call updateUI() or repaint() or revalidate(); as the table is added but the UI is not getting refreshed.
//Global Declaration
private Vector<Vector<String>> data; //used for data from database
private Vector<String> header; //used to store data header
private int count=0;
//Display only header on form load
//create header for the table
header = new Vector<String>();
header.add("Column1");
header.add("Column2");
...
model=new DefaultTableModel(data,header);
table = new JTable(model);
//in actionPerformed()
public void actionPerformed(ActionEvent ae){
if(ae.getSource()==yourMenuItem){
data=get();
for(int i=0;i<count;i++){
Object[] d={data.get(i).get(0),data.get(i).get(1),data.get(i).get(2)};
model.addRow(d);
}
}
}
This will help you to get data from database
get(){
Vector<Vector<String>> doublevector = new Vector<Vector<String>>();
Connection conn = dbConnection();//Your Database connection code
PreparedStatement pre1 = conn.prepareStatement("select * from Table");
ResultSet rs1 = pre1.executeQuery();
while(rs1.next())
{
Vector<String> singlevector = new Vector<String>();
singlevector.add(rs1.getString(1));
singlevector.add(rs1.getString(2));
....
doublevector.add(singlevector);
count++
}
return doublevector;
}
I want to display a TextField only when user has entered a value in Input field
Here is my code:
import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class PlayingAround {
JFrame frame;
JTextField display;
JTextField input;
public static void main(String[] args) {
PlayingAround obj = new PlayingAround();
obj.create();
}
private void create() {
frame = new JFrame();
display = new JTextField();
input = new JTextField();
display.setEditable(false);
display.setVisible(false);
input.addKeyListener(new Listener());
frame.add(BorderLayout.NORTH, display);
frame.add(BorderLayout.SOUTH, input);
frame.setSize(300, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class Listener implements KeyListener {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
display.setVisible(true);
display.setText(input.getText());
}
}
}
But my problem is that the Display JTextField doesn't becomes visible until there are some events like Resizing the Window, Minimizing and maximizing the Window.
I tried calling frame.repaint() in the keyReleased Method but even it has not helped.
You should call revalidate() and repaint() on the container that holds the JTextField after placing the text field component in the container. The revalidate() call sends a request to the container's layout managers to re-layout its components. The repaint() then requests that the JVM request of the paint manager to redraw the newly laid out container and its child components. The repaint() is not always needed but is usually a good idea.
Also, don't use a KeyListener for this, but rather a DocumentListener on the first text component's Document. This way, if the user empties the first text component, you can make the second text component disappear if desired. Also, text can be entered without key presses, and you want to allow for that.
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.