Adding JTextFields and JLabels dynamically by selecting JComboBox option - java

I want to write a program that allows user to connect,view and add or delete values from database. I'm stuck with the swing part. When i select a combobox option nothing happens but i want to create a view like mysql workbench. It suppose to be like that; user picks a table name from combobox and can see column names from that table and textfields to add new values or existing values above column names.
My code is this so far:
public class DBC extends JFrame{
static String tablo;
static JTextField tf = new JTextField(20);
static int columnCount;
static JPanel tfPanel = new JPanel();
static JLabel depName = new JLabel("Name");
static JLabel depLocation = new JLabel("Location");
static Box box = new Box(BoxLayout.Y_AXIS);
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection connect = DriverManager.getConnection("jdbc:mysql://localhost:3306/project"
,"root","123456789");
final Statement statement = connect.createStatement();
JLabel tabloSec = new JLabel("Tablo Seçin:");
final JComboBox<String> tablolar = new JComboBox<String>();
DatabaseMetaData md = connect.getMetaData();
final ResultSet rs = md.getTables(null, null, "%", null);
while (rs.next()) {
tablolar.addItem(rs.getString(3));
}
tablolar.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
tablo = tablolar.getSelectedItem().toString();
try {
columnCount = rs.getMetaData().getColumnCount();
for(int i=0;i<=columnCount;i++ ){
box.add(tf);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
JButton ekle = new JButton("Ekle");
ekle.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
try {
switch(tablo){
case "department":
statement.executeUpdate("INSERT INTO department(Name,Location) VALUES('"+tf.getText()+"')");
case "employee":
statement.executeUpdate("INSERT INTO employee(Id,FirstName,LastName,Sex,Address,Email,Salary,BirthDate,JoinDate) VALUES('"+tf.getText()+"')");
case "engineer":
statement.executeUpdate("INSERT INTO engineer(EngineerType) VALUES('"+tf.getText()+"')");
case "manager":
statement.executeUpdate("INSERT INTO manager(Department) VALUES('"+tf.getText()+"')");
case "project":
statement.executeUpdate("INSERT INTO project(Name,Number,Value) VALUES('"+tf.getText()+"')");
case "secretary":
statement.executeUpdate("INSERT INTO secretary(TypingSpeed) VALUES('"+tf.getText()+"')");
}
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
JButton cik = new JButton("Çık");
cik.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
JPanel panel = new JPanel(new GridLayout(4,3));
panel.add(tabloSec);
panel.add(tablolar);
panel.add(box);
panel.revalidate();
panel.add(ekle);
panel.add(cik);
JFrame frame = new JFrame("Deneme");
frame.setSize(600,600);
frame.setLocationRelativeTo(null);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}

Looks like you're adding the same text field when iterating over the metadata of the result set: box.add(tf);. This will add the same text field only once. You also need to validate() and repaint() the box container after adding new controls to it. Note that you also need to remove all controls from the box container when selecting new table. You may need to introduce scroll pane. In addition, SQL statement execution refers to the same text field. Unless of course there is only one column and one value that is always should be updated.
All in all, unless this is a very specific solution for a very specific set of tables, you may consider using friendlier controls for this, perhaps a list or a table. Maybe something similar to a properties table where first column specifies the name of the property, and the second column the value of that property. The value column is editable. You can repopulate the properties table once new SQL table is selected. Then on statement execution, just collect all the necessary values. As an alternative, you can also show the relevant view of a SQL table and let user tweak whatever values and then update SQL once done. Look at Table From Database by #camickr.
Also note that you should not execute SQL statements on Event Dispatch Thread, this may freeze your UI as long operations will block EDT. These operations should be handled on an auxiliary worker thread. See Event Dispatch Thread. It is common to use SwingWorker to handle such lengthy tasks.

Related

Populate JTable on press of TAB key

I have a JTable. User will enter an ID in a particular column and press TAB. I need to add event on that column to fetch value from DB and populate the rest of the columns of that row and create a new row for the next entry.
I am new to Swing and its difficult to find what is the best way to do it as i can see examples which were written in 2010 or so. Not sure if thats relevant still.
What I don't know:
adding event handler to a particular column's cell in table.
add next row after populating the data.
You can use a TableModelListener for this. When user change ID column value, tableChanged() is invoked. Then the relevant data is fetched from the DB and set in the row. And a new row is added as well. Try below example.
(For demonstration purpose I have used a mock database in this example. It only gives rows for IDs "111" and "222".)
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.DefaultTableModel;
import java.util.Vector;
public class TableDataChange
{
public static void main(String[] args)
{
DefaultTableModel tableModel = new DefaultTableModel(
new Object[][] {{"", "", ""}},
new Object[] {"ID", "Column 2", "Column 3"});
tableModel.addTableModelListener(new TableModelListener()
{
#Override
public void tableChanged(TableModelEvent e)
{
String id = (String) tableModel.getValueAt(e.getFirstRow(), 0);
if (id != null)
{
Vector row = Database.loadRowForId(id);
tableModel.getDataVector().set(e.getFirstRow(), row);
tableModel.addRow(new Vector());
}
}
});
JTable table = new JTable(tableModel);
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new JScrollPane(table));
f.setBounds(300, 200, 400, 300);
f.setVisible(true);
}
}
// Mock database
class Database
{
static Vector loadRowForId(String id)
{
Vector row = new Vector();
if (id.equals("111"))
{
row.add("111");
row.add("aaa");
row.add("bbb");
}
else if (id.equals("222"))
{
row.add("222");
row.add("ppp");
row.add("qqq");
}
return row;
}
}
You can try something like this,
//Add Key Listener
table.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent event) {
if (event.getKeyChar() == KeyEvent.VK_TAB) {
int selectedColumn = table.getSelectedColumn();
//Now you can search records related to ID and populate the table
}
}
});

Dispose_on_Close closes JFrame but it is still active

I am writing a program where I need to open a JFrame if a button is clicked. I set the default close operation to Dispose_on_close so that when I close the window the program doesn't shutdown completely.
In the frame that will be opened, i want to put a JTable, so I wrote two methods, a createFrame() method and a mechanicListTableProperties() which is the method that creates the JTable and adds elements to it. I then call the mechanicListTableProperties inside the createFrame() and the createFrame inside the actionPerformed() method. When I open the frame 1 time, the table is shown inside the window, but if I close and reopen the frame, the table is also readded and I see 2 tables, when I am trying to just see the one table again. Here is my source code:
public class SeeMechanicsButtonHandler implements ActionListener {
JFrame mechanicListFrame;
boolean isOpen = false;
JTable mechanicListTable;
JPanel tablePanel = new JPanel(new GridLayout());
JScrollPane sp;
List<String> names = new ArrayList<String>();
String[] namesArray;
public void createFrame() {
mechanicListFrame = new JFrame();
mechanicListFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
mechanicListFrame.setSize(new Dimension(500,500));
mechanicListFrame.add(tablePanel);
mechanicListFrame.setVisible(true);
//Prevents the window from being opened multiple times
mechanicListFrame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {
isOpen = false;
}
});
}
public void mechanicListTableProperties(){
mechanicListTable = new JTable(){
public boolean isCellEditable(int row, int column) {
return false;
}
};
DefaultTableModel model = new DefaultTableModel();
model.addColumn("Nome", namesArray);
//Creates a column with title as Nome and lines as the array
mechanicListTable.setModel(model); //adds column to the the table
mechanicListTable.setBounds(30, 40, 200, 300); //table size
mechanicListTable.setFont(new Font("Arial Rounded MT", Font.BOLD, 15));
// adding it to JScrollPane
sp = new JScrollPane(mechanicListTable);
tablePanel.add(sp);
}
public void actionPerformed(ActionEvent e) {
if(!isOpen) {
try {
//SQL code to get the data from mechanics table
ResultSet rs = ServerConnection.createQueryStatement("SELECT * FROM mechanics");
while (rs.next()){
//loop to add each entry in the table to an array list
names.add(rs.getString("nome"));
}
//creates an array to put the values from the arraylist
namesArray = new String[names.size()];
for (int iterate = 0; iterate < names.size(); iterate++){
//loop that iterates through the arraylist and puts the values in the array
namesArray[iterate] = names.get(iterate);
System.out.println(namesArray[iterate]);
//prints to the console for testing purposes
}
} catch (SQLException e1) {
e1.printStackTrace();
}
createFrame();
isOpen = true;
}
}
}

Why is nothing is displayed on JPanel?

I am trying to fetch data from the database and publish the result on a JPanel.
Here is the simplified code:
public class LedgerView extends JPanel {
public LedgerView() {
super();
this.setLayout(new FlowLayout());
this.add(new JLabel("ITEMS:"));
String JDBC_DRIVER = "com.mysql.jdbc.Driver";
String DB_URL = "jdbc:mysql://localhost/gnufinance";
String USERNAME = "gnufinance";
String PASSWORD = "gnuisnotunix";
Connection conn = null;
try {
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
} catch (Exception e) {
e.printStackTrace();
}
String query = "SELECT * FROM transactions";
try {
PreparedStatement ps = conn.prepareStatement(query);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
String desc = rs.getString(3);
System.out.println(desc);
this.add(new JLabel(desc));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
JFrame view = new JFrame();
view.setVisible(true);
view.setSize(300, 300);
view.add(new LedgerView(), BorderLayout.CENTER);
}
Nothing is displayed except a blank grayed frame, but when I remove the JDBC code, the first JLabel(ITEMS) is displayed. There is nothing on the screen but the System.out.println in the while loop prints all the data properly on the console. There are no exceptions.
You have to create the panel on the Event Dispatch Thread, or EDT.
Swing is not Thread Safe; any changes that you make to swing controls (such as creating new JLabels), must occur on the EDT (which is not the thread your main method starts on. You use EventQueue.invokeLater() to tell Java to move the work onto the Swing drawing thread.
Note that most of the time you do not want your work (like accessing a database) to occur on the EDT because it will make your user interface unresponsive. In other words, your program will be doing the work of accessing the database when it could, instead, be drawing your screen.
This code will fix your immediate problem, but you should consider accessing the database somewhere else (perhaps, for now, in your main method), storing the result in a List, and then passing the List to your LedgerView, which will result in a more responsive user interface.
public static void main(String[] args) {
final JFrame view = new JFrame();
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
view.setSize(300, 300);
view.add(new LedgerView(), BorderLayout.CENTER);
view.setVisible(true);
}
}
}

Custom navigation over rows of a JTable

How to go to last row in JTable when we press Up key at first row and also how to go to first row when we press Down key at last row? Like Enter key does when we press Enter key at last row it will go to the first row.
I already done this coding but it just show data to text field:
private void jtKeyReleased(java.awt.event.KeyEvent evt) {
if(evt.getKeyCode()==KeyEvent.VK_DOWN ||evt.getKeyCode()==KeyEvent.VK_UP){
int row=jt.getSelectedRow();
String TableClick=(jt.getModel().getValueAt(row,0).toString());
try{
String sql="select Product,Roo,TotalStock from pro where
Product='"+TableClick+ "'";
PreparedStatement pst = (PreparedStatement)
conn.prepareStatement(sql);
ResultSet res = pst.executeQuery();
if(res.next()){
String add1=res.getString("Product");
proo.setText(add1);
// String add2=res.getString("Id");
//idd.setText(add2);
String add3=res.getString("Roo");
rooo.setText(add3);
String add4=res.getString("TotalStock");
stkk.setText(add4);
abc=res.getString("TotalStock");
}
} catch(Exception e) {
} //catch
} // if
}
You need to create two custom Actions:
one Action to wrap from the first row to the bottom and
another Action to wrap from the bottom to the top.
The easiest way to do this is to take advantage of existing Actions defined in JTable. The UP keys move up one line at a time and the Down key moves down one line at a time. You can also use CTRL+HOME to go to the top line and CTRL_END to go to the last line.
So I would suggest to start with the UP Action and modify it to implement the CTRL+END Action. The easiest way to do this is to take advantage of the concept of Wrapping Actions. This class is a wrapper class for an existing Action and allows you to add custom code to enhance the Action.
import java.awt.event.*;
import javax.swing.*;
public class UpAction extends WrappedAction implements ActionListener
{
private JTable table;
private Action endAction;
/*
* Specify the component and KeyStroke for the Action we want to wrap
*/
public UpAction(JTable table, KeyStroke keyStroke)
{
super(table, keyStroke);
this.table = table;
endAction = table.getActionMap().get("selectLastRow");
}
/*
* Provide the custom behaviour of the Action
*/
public void actionPerformed(ActionEvent e)
{
if (table.getSelectedRow() == 0)
endAction.actionPerformed( e );
else
invokeOriginalAction( e );
}
private static void createAndShowGUI()
{
JTable table = new JTable(7, 5);
new UpAction(table, KeyStroke.getKeyStroke("UP"));
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new JScrollPane(table) );
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
You would need to create a similar Action for the DOWN functionality. Note the action string name for selecting the first row is: selectFirstRow. Check out Key Bindings for a list of all the Actions used by a given component.

ActionListener on JOptionPane

I am following the Oracle tutorial on how to create a custom dialog box: http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html
I have two buttons: Save Object and Delete Object which when clicked should execute a certain piece of code. Unfortunately I can't seem to add any ActionListener to the JOptionPane buttons so when they're clicked nothing happens.
Can anyone help tell me how I can go about doing this? Here is the class I have for the dialog box so far:
class InputDialogBox extends JDialog implements ActionListener, PropertyChangeListener {
private String typedText = null;
private JTextField textField;
private JOptionPane optionPane;
private String btnString1 = "Save Object";
private String btnString2 = "Delete Object";
/**
* Returns null if the typed string was invalid;
* otherwise, returns the string as the user entered it.
*/
public String getValidatedText() {
return typedText;
}
/** Creates the reusable dialog. */
public InputDialogBox(Frame aFrame, int x, int y) {
super(aFrame, true);
setTitle("New Object");
textField = new JTextField(10);
//Create an array of the text and components to be displayed.
String msgString1 = "Object label:";
Object[] array = {msgString1, textField};
//Create an array specifying the number of dialog buttons
//and their text.
Object[] options = {btnString1, btnString2};
//Create the JOptionPane.
optionPane = new JOptionPane(array,
JOptionPane.PLAIN_MESSAGE,
JOptionPane.YES_NO_OPTION,
null,
options,
options[0]);
setSize(new Dimension(300,250));
setLocation(x, y);
//Make this dialog display it.
setContentPane(optionPane);
setVisible(true);
//Handle window closing correctly.
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
/*
* Instead of directly closing the window,
* we're going to change the JOptionPane's
* value property.
*/
optionPane.setValue(new Integer(
JOptionPane.CLOSED_OPTION));
}
});
//Ensure the text field always gets the first focus.
addComponentListener(new ComponentAdapter() {
public void componentShown(ComponentEvent ce) {
textField.requestFocusInWindow();
}
});
//Register an event handler that puts the text into the option pane.
textField.addActionListener(this);
//Register an event handler that reacts to option pane state changes.
optionPane.addPropertyChangeListener(this);
}
/** This method handles events for the text field. */
public void actionPerformed(ActionEvent e) {
optionPane.setValue(btnString1);
System.out.println(e.getActionCommand());
}
/** This method reacts to state changes in the option pane. */
public void propertyChange(PropertyChangeEvent e) {
String prop = e.getPropertyName();
if (isVisible()
&& (e.getSource() == optionPane)
&& (JOptionPane.VALUE_PROPERTY.equals(prop) ||
JOptionPane.INPUT_VALUE_PROPERTY.equals(prop))) {
Object value = optionPane.getValue();
if (value == JOptionPane.UNINITIALIZED_VALUE) {
//ignore reset
return;
}
//Reset the JOptionPane's value.
//If you don't do this, then if the user
//presses the same button next time, no
//property change event will be fired.
optionPane.setValue(JOptionPane.UNINITIALIZED_VALUE);
if (btnString1.equals(value)) {
typedText = textField.getText();
String ucText = typedText.toUpperCase();
if (ucText != null ) {
//we're done; clear and dismiss the dialog
clearAndHide();
} else {
//text was invalid
textField.selectAll();
JOptionPane.showMessageDialog(
InputDialogBox.this,
"Please enter a label",
"Try again",
JOptionPane.ERROR_MESSAGE);
typedText = null;
textField.requestFocusInWindow();
}
} else { //user closed dialog or clicked delete
// Delete the object ...
typedText = null;
clearAndHide();
}
}
}
/** This method clears the dialog and hides it. */
public void clearAndHide() {
textField.setText(null);
setVisible(false);
}
I think you're missing the point of the JOptionPane. It comes with the ability to show it's own dialog...
public class TestOptionPane02 {
public static void main(String[] args) {
new TestOptionPane02();
}
public TestOptionPane02() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JTextField textField = new JTextField(10);
String btnString1 = "Save Object";
String btnString2 = "Delete Object";
//Create an array of the text and components to be displayed.
String msgString1 = "Object label:";
Object[] array = {msgString1, textField};
//Create an array specifying the number of dialog buttons
//and their text.
Object[] options = {btnString1, btnString2};
int result = JOptionPane.showOptionDialog(null, array, "", JOptionPane.YES_NO_OPTION, JOptionPane.PLAIN_MESSAGE, "New Object", options, options[0]);
switch (result) {
case 0:
System.out.println("Save me");
break;
case 1:
System.out.println("Delete me");
break;
}
}
});
}
}
To do it manually, you're going to have to do a little more work.
Firstly, you're going to have to listen to the panel's property change events, looking for changes to the JOptionPane.VALUE_PROPERTY and ignoring any value of JOptionPane.UNINITIALIZED_VALUE...
Once you detect the change, you will need to dispose of your dialog.
The you will need extract the value that was selected via the JOptionPane#getValue method, which returns an Object. You will have to interrupt the meaning to that value yourself...
Needless to say, JOptionPane.showXxxDialog methods do all this for you...
Now if you worried about having to go through all the setup of the dialog, I'd write a utility method that either did it completely or took the required parameters...but that's just me
UPDATED
Don't know why I didn't think it sooner...
Instead of passing an array of String as the options parameter, pass an array of JButton. This way you can attach your own listeners.
options - an array of objects indicating the possible choices the user
can make; if the objects are components, they are rendered properly;
non-String objects are rendered using their toString methods; if this
parameter is null, the options are determined by the Look and Feel
For the flexibility you seem to want you should have your class extend JFrame instead of JDialog. Then declare your buttons as JButtons:
JButton saveButton = new JButton("Save"); and add an actionListnener to this button:
saveButton.addActionListener();
either you can put a class name inside the parenthesis of the saveButton, or you can simply pass it the keyword 'this' and declare a method called actionPerformed to encapsulate the code that should execute when the the button is pressed.
See this link for a JButton tutorial with more details:
http://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html

Categories

Resources