How to position Java swing components when there is a JScrollPane - java

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.

Related

I'm making a Java interactive novel, but my JTextArea Disappears

My adventure game has a bunch of nested if statements to output something based on the input, but my JTextField only gets one input and then disappears. I want to get the JTextField to take unlimited inputs and use .append to to show them in the jtextarea. I want to have the program continue to take user inputs until the story path in the if statements end. If want to get input from a JTextField and put the output in the JTextArea and keep it there.
import java.awt.Dimension;
import java.awt.Font;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;
import java.util.Scanner;
import java.io.Reader;
import javax.swing.*;
import javax.swing.text.BadLocationException;
/*JakeBarcelona
*Date:May 5, 2016
*Program Name:StoryTester.java
*Description:
*/
public class StoryTester extends JFrame
{
static JTextField input = new JTextField(30);
static JTextArea fields = new JTextArea(30,50);
static Story ARoom=new Story();
public static void main(String[] args) throws BadLocationException
{
JFrame frame = new JFrame();
String story=new String();
JLabel intro = new JLabel(story);
//Sets the JLabels font and color
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//puts a red x to close it
Story wow = new Story();
String introduction=wow.intro();
//creates array field for text editing
fields.insert(introduction, 0);
String name= fields.getText(0,30);
//creates new Panel
JPanel myPanel=new JPanel();
//creates label for text box
myPanel.setPreferredSize(new Dimension(600,600));
myPanel.add(fields);
myPanel.add(input);
//puts a scroll bar and cancel and ok button
JScrollPane scroll = new JScrollPane(fields, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
myPanel.add(scroll);
int result = JOptionPane.showConfirmDialog(null, myPanel, "Story", JOptionPane.OK_CANCEL_OPTION);
if(result==JOptionPane.OK_OPTION);
{
String jake = input.getText();
String need = ARoom.storyStatements(jake);
System.out.println(need);
fields.append(need);
}
}
}
You are adding fields twice to the GUI, once to myPanel and once to the JScdrollPane, scrool, which is then added to myPanel. Don't do this, but rather add it to the JScrollPane only. You're also artificially constraining the size of your myPanel JPanel, and this is likely what's getting you into trouble.
Instead use layouts in a smart way by for instance giving myPanel a BorderLayout, adding the JScrollPane to the BorderLayout.CENTER position and the inputs JTextField to the BorderLayout.PAGE_END position. And don't set the preferred size of myPanel but rather let the text component column and row properties set their preferred size which will in turn set the preferred size of the myPanel JPanel.
Also you're using static fields inappropriately and in fact none of your current fields should be static.
For example
import java.awt.BorderLayout;
import javax.swing.*;
public class LayoutEg extends JPanel {
private static final int COLS = 50;
private static final int ROWS = 30;
private JTextField input = new JTextField(COLS);
private JTextArea fields = new JTextArea(ROWS, COLS);
public LayoutEg() {
// two methods below so that words wrap
fields.setWrapStyleWord(true);
fields.setLineWrap(true);
fields.setFocusable(false); // so we can't write directly into JTextArea
JScrollPane scrollPane = new JScrollPane(fields);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
setLayout(new BorderLayout(2, 2));
add(scrollPane, BorderLayout.CENTER);
add(input, BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
LayoutEg mainPanel = new LayoutEg();
JFrame frame = new JFrame("Story GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}

How do I remove the A on the top of the JTable inside a JScrollPane?

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.

How to refresh data in Jscrollpane bound with jtable?

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.

Is there a way to create Table in Java AWT?

Is there way to create Table in Java AWT? I need to create simple Java AWT program for insert, edit, delete and read users from database.
Yes: Make your own table with a bunch of labels as cells, and a scroll pane. You can set it up to add more cells/labels on the fly, and add any features you want.
If you cannot or do not want to do the above, then you can seek out a third party library that creates tables for AWT.
Or take the much easier and faster option and just use swing.
you can make table in swing JTable. But now you should use Graphics:
import java.awt.*;
public class name extends Frame{
name(){
setLayout(new FlowLayout());
setSize(1000,1000);
setVisible(true);
}//end of name()
public void paint(Graphics g){//opening graphics
g.drawRect(10,50,100,100);//make a rectangle
g.drawRect(50,50,100,100);//another rectangle
g.drawRect(10,100,100,100);//and another
g.drawRect(50,100,100,100);//last rectangle
g.drawString("SOMTHING", 30,80);//write a text in a rectangle
}//end of graphics
public static void main(String[] args){
name n=new name();
}
}//end of Frame
You can create using a Panel with GridLayout, with the components (Labels or TextFields) and then you can place that panel inside your frame. Here is the example code! Hope this will work!
But the only problem is, we cannot set the size for the components which we placed in a GridLayout! Anyone knows how to set the size of the component in GridLayout, please leave a comment!
import java.awt.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class AwtTable extends Frame{
AwtTable(){
Panel p = new Panel();
Color c = new Color(241, 216, 252);
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/database","root","password");
PreparedStatement ps = con.prepareStatement("select * from table_name;");
ResultSet rs = ps.executeQuery();
TextField l1 =null,l2=null,l3=null,l4=null,l5=null,l6=null ;
int row=1;
while(rs.next()) {
l1 = new TextField();
l1.setText(rs.getString(1));
l2 = new TextField();
l2.setText(rs.getString(2));
l3 = new TextField();
l3.setText(Integer.toString(rs.getInt(3)));
l4 = new TextField();
l4.setText(rs.getString(4));
l5 = new TextField();
l5.setText(rs.getString(5));
l6 = new TextField();
l6.setText(Long.toString(rs.getLong(6)));
Button add = new Button("Edit");
Button delete = new Button("Delete");
add.setSize(70,20);
delete.setSize(70,20);
p.add(l1);p.add(l2);p.add(l3);p.add(l4);p.add(l5);p.add(l6);
p.add(add);p.add(delete);
p.setLayout(new GridLayout(row,8));
row++;
}
p.setBackground(Color.white);
p.setBounds(100,100,1000,400);
add(p);
setLayout(null);
setVisible(true);
setSize(700,500);
setTitle("Employee Datas");
setBackground(c);
}catch(Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) {
AwtTable at = new AwtTable();
}
}

JComboBox and JTable in java applet

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.

Categories

Resources