Making a query result table (GUI) using Java - java

I have a panel where the user will search for a customer by entering a surname or ID. I want to implement some kind of table that displays each row of SQL query results. What's the best way to do this? The first thing that comes to my mind would be to use a multi-dimensional array and a JTextArea. What do you think?

Have you looked into a JTable?
Edit: This is my first time replying so I guess I'll notice when I do something wrong. I have recently created something similar to what you are aiming for, so this piece of code might set you on your way:
String[][] results = null;
if(query != null){
results = domeinController.Search(query);
} else {
results = domeinController.ReturnAllAccounts();
txtSearch.setText("");
}
TableModel table = new DefaultTableModel(results, new String[] {d("LBL_SERVICE"), d("LBL_ACC_NAME"), d("LBL_PASSWORD"), d("LBL_EMAIL")});
tblResults = new JTable(){
public boolean isCellEditable(int roxIndex, int colIndex){
return false;
}
};
jScrollPane1.setViewportView(tblResults);
tblResults.setModel(table);
tblResults.setAutoCreateRowSorter(true);
tblResults.setBounds(55, 145, 423, 228);
tblResults.getTableHeader().setAutoscrolls(true);
tblResults.getTableHeader().setReorderingAllowed(false);
tblResults.getTableHeader().setResizingAllowed(false);
tblResults.setShowVerticalLines(false);
tblResults.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent evt) {
tblResultsMousePressed(evt);
}
});
Basically you create a tableModel with a 2D Array of data as your 1st parameter, and an array with headers for your 2nd parameter. After that you can specify behaviour to your table.

I highly recommend taking Glazed List into account.
It's a library which takes care of the most of the heavylifting related to presenting tabular data in a table with both filtering and sorting. It also provides a multithreading-safe datamodel. Using bare Swing and Java it's a lot lot harder to implement it all correctly.
Here is a nice tutorial provided. Once anybody starts writing CRUD GUIs, sooner or later all end up wanting so called "standard features" which all table oriented guis share in common. Why wasting time inventing it all and risking making a lot of mistakes, when you can build upon proven solutions. Especially, when it's so easy.
An example, displaying a XML based JTable:
import java.util.*;
import java.io.*;
import javax.swing.*;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
// a simple issues library
import ca.odell.issuezilla.*;
// glazed lists
import ca.odell.glazedlists.*;
import ca.odell.glazedlists.swing.*;
/**
* An IssueBrowser is a program for finding and viewing issues.
*
* #author <href="mailto:jesse#odel.on.ca">Jesse Wilson</a>
*/
public class IssuesBrowser {
/** event list that hosts the issues */
private EventList issuesEventList = new BasicEventList();
/**
* Create an IssueBrowser for the specified issues.
*/
public IssuesBrowser(Collection issues) {
issuesEventList.addAll(issues);
}
/**
* Display a frame for browsing issues.
*/
public void display() {
// create a panel with a table
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
EventListModel issuesListModel = new EventListModel(issuesEventList);
JList issuesJList = new JList(issuesListModel);
JScrollPane issuesListScrollPane = new JScrollPane(issuesJList);
panel.add(issuesListScrollPane, new GridBagConstraints(...));
// create a frame with that panel
JFrame frame = new JFrame("Issues");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(540, 380);
frame.getContentPane().add(panel);
frame.show();
}
/**
* Launch the IssuesBrowser from the commandline.
*/
public static void main(String[] args) {
if(args.length != 1) {
System.out.println("Usage: IssuesBrowser <file>");
return;
}
// load some issues
Collection issues = null;
try {
IssuezillaXMLParser parser = new IssuezillaXMLParser();
InputStream issuesInStream = new FileInputStream(args[0]);
issues = parser.loadIssues(issuesInStream, null);
issuesInStream.close();
} catch(IOException e) {
e.printStackTrace();
return;
}
// create the browser
IssuesBrowser browser = new IssuesBrowser(issues);
browser.display();
}
}

Related

Checking input validity BEFORE saving to JTable Cell

I would like to check the validity of user input every time they change a value on the JTable. The method I thought of is similar to this simplified sample code:
public static void main(String[] args) {
JFrame main = new JFrame();
JTable table = new JTable(6, 4);
table.setSize(300, 300);
table.getModel().addTableModelListener((TableModelEvent e) -> {
Object s = e.getSource();
TableModel d = (TableModel) s;
if(!checkValid(d.getValueAt(e.getFirstRow(), e.getColumn())))
{
d.setValueAt(" - ", e.getFirstRow(), e.getColumn());
}
});
main.add(table);
main.setSize(300,300);
main.setLocationRelativeTo(null);
main.setVisible(true);
main.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}
The code will check the input if a change in the table occurs and will revert back to "-" if the input is invalid.
However, an error will occur stating that Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError.
a.) Could someone explain the error and how to solve the issue?
b.) Or is there a better way of implementing a listener that checks the user input BEFORE exiting editing mode or saving the table?
EDIT: I have tried implementing the CellEditorListener like the sample below:
table.getCellEditor().addCellEditorListener(new CellEditorListener() {
public void editingStopped(ChangeEvent e)
{
}
public void editingCanceled(ChangeEvent e)
{
}
});
This in turn prompted an error Exception in thread "main" java.lang.NullPointerException. There isn't that much of documentation on CellEditorListener and didn't quite understood on how it works and how to use it.
According to the corresponding section of the corresponding Java tutorials, you can override stopCellEditing of DefaultCellEditor to return false if the editor should not lose focus or true otherwise. Which means we can use it to check user input first and then, according to the user's input, return false if he/she enters invalid text (or true if he/she enters valid one).
In the following example code I'm using a JTextField, which lets the users type whatever they want and then checks the user's input in stopCellEditing to be non-empty (as defined by my static checkValid method, but you can obviously alter it according to your needs):
import java.awt.Toolkit;
import javax.swing.DefaultCellEditor;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
public class Main {
public static boolean checkValid(final String text) {
return text != null && !text.trim().isEmpty(); //Your checks here...
}
public static class MyCellEditor extends DefaultCellEditor {
public MyCellEditor() {
super(new JTextField());
}
#Override
public boolean stopCellEditing() {
final JTextField field = (JTextField) getComponent();
if (checkValid(field.getText())) {
//field.setBackground(Color.WHITE);
return super.stopCellEditing(); //Fires 'editing stopped' event and returns true.
}
Toolkit.getDefaultToolkit().beep();
//field.setBackground(Color.ORANGE.darker());
JOptionPane.showMessageDialog(field, "You must enter a non-empty value!", "Oups!", JOptionPane.ERROR_MESSAGE);
return false;
}
}
public static void main(final String[] args) {
final JTable table = new JTable(new DefaultTableModel(10, 10));
table.setDefaultEditor(Object.class, new MyCellEditor());
final JFrame frame = new JFrame("JTable DefaultEditor");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(table);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
I use DefaultTableModel for easy initialization of the table. It also returns that each cell in the table is editable (we obviously need at least one cell to be editable, in order to check the validity of the program). Every cell starts initially empty, but the cell editor won't let you leave it empty, if you start an editing event.
An alternative solution could be to add an InputVerifier in the JTextField of the editor, but this would be a bit more tricky as I tested it, so I would rather not post it here in favor of the better above solution (and also suggested by the Java tutorial).

How to properly separate GUI from the Logic in this Java Swing code

I am trying to learn a bit about GUI interfaces with swing and how to construct a GUI program correctly, at least in the most efficient way depending on the project of course.
Here in this example, I try to create a simple program which does the following.
I have a Menu consisting of 2 buttons, each button when is pressed the appropriate ActionListener is triggered and an instance of a new class is getting created.
Each new class ( the name of the 2 of them are: Journal, Seminar ) has its own GUI code consisting of text fields, buttons, and other swing components.
At first, I had the GUI classes of these 2 inside the Journal's and Seminar's Logic classes. But as I understand this is not a good practice, it seems we need to make the program components not connected so tight together.
So now I tried to move each GUI method to another class and call them in each of the classes constructors.
NOTE: the final purpose of the program is serializability of objects to file so ignore for now some of the code corresponds to it.
The code isn't functional at the moment.
** QUESTION:**
Is the approach I'm following in the entire program "correct" ? or should I find another way?
What pieces of knowledge should I pursuit so I can understand how to build this kind of apps efficiently?
How I can make the current work?
It's my first post here so I tried my best to give this question in the best way I could, let me know if you need any more info on this. Thanks!*
Any help much appreciated.
Menu Class
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
public class Menu {
JFrame menu_frame;
JButton ergasia_periodiko_btn = new JButton();
JButton ergasia_sinedrio_btn = new JButton();
Menu() {
this.menu_frame = new JFrame();
this.menu_frame.setSize(400,100);
this.menu_frame.setTitle("Ereunitikos Katalogos");
this.menu_frame.add(ergasia_periodiko_btn);
this.menu_frame.add(ergasia_sinedrio_btn);
this.menu_frame.setLayout(new FlowLayout());
this.ergasia_periodiko_btn.setText("Periodika");
this.ergasia_sinedrio_btn.setText("Sinedria");
this.ergasia_periodiko_btn.addActionListener(e -> new Journal()); //Action Listener to Joyrnal
this.ergasia_sinedrio_btn.addActionListener(e -> {
try {
new Seminar();
} catch (IOException e1) {
e1.printStackTrace();
}
}); //Action Listener to Seminar
this.menu_frame.setLocationRelativeTo(null);
this.menu_frame.setVisible(true);
}
public static void main(String[] args)
{ new Menu(); }
}
Journal Class
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Journal implements Serializable
{
Journal_GUI gui; //**Creating instance of journal gui inside here so i can run the gui code in the constructor**
String column_title;
List writers = new ArrayList(2);
String mag_title;
String numberOfPages;
String released_date;
String volume;
String exact_page;
Journal(){}
public void fillVars()
{
this.column_title = gui.column_title_tf.getText();
this.writers = Collections.singletonList(gui.writers_tf.getText());
this.mag_title = gui.mag_title_tf.getText();
this.numberOfPages = gui.numberOfPages_tf.getText();
this.released_date = gui.released_date_tf.getText();
this.volume = gui.volume_tf.getText();
this.exact_page = gui.exact_page_tf.getText();
}
public void insertP() {
fillVars();
// try {
// My_Serialization.serialization("fileToSavePeriodiko.txt", this.toString());
// }// catch (IOException e) {
// e.printStackTrace();
//}
}
public void searchP_byTitle(){}
public void searchP_byName(){}
#Override
public String toString() {
String value = "\n Periodiko column title : " + column_title + "\n writers : " + writers+ "\n Titlos magazine : " + mag_title
+ "\n Number of Pages : " + numberOfPages + "\n Released Date : " + released_date + "\n Volume : " + volume + "\n Exact Page : " + exact_page +"\n";
return value;
}
}
Journal Gui Class
import javax.swing.*;
public class Journal_GUI extends Journal{
JFrame periodikoFrame;
JTextField column_title_tf;
JTextField writers_tf;
JTextField mag_title_tf;
JTextField numberOfPages_tf;
JTextField released_date_tf;
JTextField volume_tf;
JTextField exact_page_tf;
public Journal_GUI(){
initComponenets();
}
public void initComponenets() {
periodikoFrame = new JFrame("PERIODIKA");
periodikoFrame.setSize(500, 500);
JPanel panel = new JPanel();
BoxLayout boxlayout = new BoxLayout(panel, BoxLayout.Y_AXIS);
panel.setLayout(boxlayout);
column_title_tf = new JTextField("Column Title");
writers_tf = new JTextField("Writers");
mag_title_tf = new JTextField("Magazine's Title");
numberOfPages_tf = new JTextField("Number of Pages");
released_date_tf = new JTextField("Date of Release");
volume_tf = new JTextField("Volume");
exact_page_tf = new JTextField("Exact Page");
JButton search_mag_btn_byName = new JButton("Search By name");
JButton search_mag_btn_byTitle = new JButton("Search By Title");
JButton insert_mag_btn = new JButton("Insert article");
search_mag_btn_byName.addActionListener(e -> searchP_byName());
search_mag_btn_byTitle.addActionListener(e -> searchP_byTitle());
insert_mag_btn.addActionListener(e -> insertP());
panel.add(column_title_tf);
panel.add(writers_tf);
panel.add(mag_title_tf);
panel.add(numberOfPages_tf);
panel.add(released_date_tf);
panel.add(volume_tf);
panel.add(exact_page_tf);
panel.add(search_mag_btn_byName);
panel.add(search_mag_btn_byTitle);
panel.add(insert_mag_btn);
periodikoFrame.setLocationRelativeTo(null);
periodikoFrame.add(panel);
periodikoFrame.setVisible(true);
}
}
Is the approach I'm following in the entire program "correct" ? or
should I find another way?
It's probably correct, but not the easiest to understand & develop
What pieces of knowledge should I pursuit so I can understand how to
build this kind of apps efficiently?
You should take a look at https://en.wikipedia.org/wiki/SOLID, especially at https://en.wikipedia.org/wiki/Dependency_inversion_principle#Model_View_Controller and https://en.wikipedia.org/wiki/Single_responsibility_principle in your case.
This should give you some hint how to build app efficiently ( this one included ).
How I can make the current work?
Do you mean to serialize an object to a file ? If that's the case, look at How to write and read java serialized objects into a file
Just a suggestion, when I started developing GUI based desktop applications for the first time I used Eclipse WindowsBuilder plugin, it generates code itself all you have to do is drag and drop the components you need. Or even better you can to start it go with NetBeans, it has pretty good GUI builtin toolkit (drag and drop), use it understand how it generates automatic code and follow that to be good at what you are trying to do here.

What is an advisable design pattern for switching between GUI pages?

What I don't like about my code below is:
getters are needed for every JButton on each page
the actionPerformed method can quickly become bloated with if-else statements
So, is there a better way to control all GUI actions from a single class?
If I define an actionPerformed method within each respective page (JPanel), each page will need access to instances of the page(s) switched to, and I am trying to avoid using the Singleton pattern for each page...
Here is the code:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
*
* #author Ian A. Campbell
*
*/
public class Controller implements ActionListener {
/**
* instance variables:
*/
private Frame frame;
private OptionPage firstPage;
private FirstOptionPage firstOption;
private SecondOptionPage secondOption;
/**
*
*/
public Controller() {
// instantiating the frame here:
this.frame = new Frame();
/*
* instantiating all pages here:
*
* NOTE: passing "this" because this class
* handles the events from these pages
*/
this.firstPage = new OptionPage(this);
this.firstOption = new FirstOptionPage(this);
this.secondOption = new SecondOptionPage(this);
}
/**
*
*/
public void start() {
this.frame.add(this.firstPage); // adding the first page
// NOTE: these lines prevent blank loading and flickering pages!
this.frame.validate();
this.frame.repaint();
this.frame.setVisible(true);
}
/**
*
* #return the JFrame instantiated from the class Frame
*/
public Frame getFrame() {
return this.frame;
}
#Override
public void actionPerformed(ActionEvent e) {
// the "first option" button from the OptionPage:
if (e.getSource() == this.firstPage.getFirstButton()) {
this.frame.getContentPane().removeAll();
this.frame.getContentPane().add(this.firstOption);
// the "second option" button from the OptionPage:
} else if (e.getSource() == this.firstPage.getSecondButton()) {
this.frame.getContentPane().removeAll();
this.frame.getContentPane().add(this.secondOption);
}
// NOTE: these lines prevent blank loading and flickering pages!
this.frame.validate();
this.frame.repaint();
this.frame.setVisible(true);
}
} // end of Controller
Use a Card Layout. Card Layout Actions adds some extra features that you might find helpful.
You could use card layout, or you could get creative and remove elements. For instance:
panel.remove((JButton)myButton1)); // Remove all of the elements...
panel.add((JButton)myButton2)); // Add the new elements
Of course I wouldn't deal with the java built in GUI at all, IMO the layout designs are horrific. I would much rather use something like "A New Look and Feel" -- http://www.javootoo.com/.

How do I use an object reference as an argument if it is instantiated after the class taking the argument?

So I have this code:
package com.erikbalen.game.rpg;
import com.erikbalen.platform.*;
import javax.swing.JFrame;
public class World extends Engine {
public static void main(String[] args) {
Gui display = new Gui(/*takes a Player argument so i can get certain variables*/);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
display.setSize(300,220);
display.setVisible(true);
Player player1 = new Dps("ebalen", display);
Player player2 = new Healer("frankypanky", display);
}
}
package com.erikbalen.game.rpg;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Gui extends JFrame implements ActionListener {
/**
*
*/
private static final long serialVersionUID = -384241835772507459L;
private JLabel playerInfo;
private JTextField textField;
private final static String newline = "\n";
private JTextArea feed;
private JScrollPane scrollPane;
private Player player;
public Gui(Player currentPlayer) {
super("Erik's RPG");
this.player = currentPlayer;
setLayout(new FlowLayout());
playerInfo = new JLabel("<html>Health = " + currentPlayer.getHealth() + " | " + "Mana = " + currentPlayer.getMana() + "</html>");
playerInfo.setBorder(BorderFactory.createTitledBorder(currentPlayer.getName()));
textField = new JTextField(20);
textField.addActionListener(this);
feed = new JTextArea(5, 20);
scrollPane = new JScrollPane(feed);
feed.setEditable(false);
add(playerInfo);
add(feed);
add(textField);
add(scrollPane);
}
public void actionPerformed(ActionEvent textBox) {
String text = textField.getText();
this.player.chat(text);
}
public void printText(String text) {
feed.append(text + "\n");
feed.setCaretPosition(feed.getDocument().getLength());
}
}
My problem is that class Gui takes a Player as an argument and Player takes Gui as an argument. How do I let both objects take each other as arguments? Feel free to tell me if my code is inefficient.
Well, ideally you should try to break the circular dependency, but otherwise, you could:
Create the GUI, create the players by passing in the GUI, then add the players to the GUI
Create the players, create the GUI by passing in the players, then set the GUI for the players
Create the GUI within the player constructor:
Player(String name)
{
GUI gui = new GUi(this);
...
}
All of these are non-ideal:
You may well want your classes to be immutable, which makes the first two options nasty
Publishing the this reference before your constructor has finished executing has various issues, both in terms of thread safety and the memory model, as well as potentially allowing the GUI constructor to call back to the Player object before it's fully initialized.
This goes back to "try to break the dependency" - but if that's really impossible, I would probably favour the first option, without knowing anything else. It makes sense to be able to add players to a game - it makes less sense to set the GUI for a player after the fact, IMO.
Your stuck in what we call a circular dependency. This is almost everytime the result of a bad design.
There are still solutions, but there are not really pretty. For an elegant way, you should rethink your design.
Does the GUI really need the player ? Maybe you could create a method to set the player later on. If it's not possible, you could also create a setter in the player. You won't be able to set both at construction time.
Try giving the Gui class methods for updating what is displayed to the user/users. Make the directing code (main() for example) responsible for updating the Gui with the right information as events happen.
Neither Gui nor Player should have to take each other as constructor arguments - Gui should only be responsible for displaying information it is told to, and Player should only be a logical representation of a game piece. Event-driven functionality should be reserved for the directing code.

Removing an item from the JList using ListModel as model type

I have the JList which is using ListModel and not the DefaultListModel. I don't want to change the type now because I am using this in many places. I want to remove a selected item from the same list. How do i do this? I am using the following code but its not working for me.
made_list.removeSelectionInterval(
made_list.getSelectedIndex(), made_list.getSelectedIndex());
--EDIT--
I am using the following code when I create my list:
made_list = new javax.swing.JList();
made_list.setModel(new DefaultListModel());
And then in the JButton mouseclick event, I am using the following code to remove the selected item from the list when the button is pressed
private void removeActionPerformed(java.awt.event.ActionEvent evt) {
//made_list.removeSelectionInterval(made_list.getSelectedIndex(),
//made_list.getSelectedIndex());
System.out.println(made_list.getModel());
DefaultListModel model = (DefaultListModel)made_list.getModel();
model.remove(1);
}
removeSelectionInterval removes nothing from the model or the list except the selection interval. The list items remain unscathed. I'm afraid that you're either going to have to extend your ListModel and give it a removeItem(...) method as well as listeners and the ability to fire notifiers, etc... a la AbstractListModel -- quite a lot of work! If it were my money, though, I'd go the easy route and simply use a DefaultListModel for my model as it is a lot safer to do it this way, a lot easier, and will take a lot less time. I know you state that you don't want to use these, but I think you'll find it a lot easier than your potential alternatives.
An example of an SSCCE is something like this:
import java.awt.event.*;
import javax.swing.*;
public class Foo1 {
private String[] elements = {"Monday", "Tueday", "Wednesday"};
private javax.swing.JList made_list = new javax.swing.JList();
public Foo1() {
made_list.setModel(new DefaultListModel());
for (String element : elements) {
((DefaultListModel) made_list.getModel()).addElement(element);
}
JButton removeItemBtn = new JButton("Remove Item");
removeItemBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
removeActionPerformed(e);
}
});
JPanel panel = new JPanel();
panel.add(new JScrollPane(made_list));
panel.add(removeItemBtn);
JOptionPane.showMessageDialog(null, panel);
}
private void removeActionPerformed(ActionEvent e) {
System.out.println("made_list's model: " + made_list.getModel());
System.out.println("Model from a fresh JList: " + new JList().getModel());
DefaultListModel model = (DefaultListModel) made_list.getModel();
if (model.size() > 0) {
model.remove(0);
}
}
public static void main(String[] args) {
new Foo1();
}
}
You've been given a link to different sections of the Swing tutorial in the past to help solve problems. This was done for a reason. It helps solve your current problem. It gives you a reference for future problems.
All you need to do is look at the Table of Contents for the Swing tutorial and you will find a section on "How to Use Lists" which has a working example that adds/removes items from a list. Please read the tutorial first.
Or if you can't remember how to find the Swing tutorial then read the JList API where you will find a link to the same tutorial.
//First added item into the list
DefaultListModel dlm1=new DefaultListModel();
listLeft.setModel(dlm1);
dlm1.addElement("A");
dlm1.addElement("B");
dlm1.addElement("C");
// Removeing element from list
Object[] temp=listRight.getSelectedValues();
if(temp.length>0)
{
for(int i=0;i<temp.length;i++)
{
dlm1.removeElement(temp[i]);
}
}

Categories