I am developing an application in Netbeans using Java and have been told to use the GUI creation features that Netbeans offer. Due to this I cannot edit the initComponents(); method to edit the creation of the JList and add a default list model to it.
I have tried creating a new JList but that resulted in an infinite loop. I haven't ever created controls through coding them myself, only by an IDE's GUI creation tools.
This is what I have currently:
private void formWindowActivated(java.awt.event.WindowEvent evt) {
//String to hold current patients data
String patientDetails;
//Take the arraylist from the model
ArrayList<IAccountStrategy> unapprovedPatients;
unapprovedPatients = model.getObservers();
//Create default list model to store the patients details
DefaultListModel<String> unapprovedPatientModel = new DefaultListModel<>();
IAccountStrategy xx;
//For loop to iterate through each element of unapprovedPatients
for(int i = 0; i < unapprovedPatients.size(); i++){
//get the current patients details and store them in a string variable
xx = unapprovedPatients.get(i);
patientDetails = xx.getAccountID() + xx.getUsername() + xx.getFirstname() + xx.getLastname();
//Add string variable to list model
unapprovedPatientModel.addElement(patientDetails);
}
//add list model to existing JList
listPatients.addElement(unapprovedPatientModel);
}
I would like to output all the elements from the list model into the actual JList and then let the user interact with the list itself.
Thanks in advance!
is it not possible to use the list as I want
You just wrote code to create the DefaultListModel.
So now all you need is to add:
list.setModel( unapprovedPatientModel );
so the JList can use the newly created model.
Although the problem with this code is that the code will be executed every time the window is activated.
But the point is that all you need to do is update the list using the setModel() method. How you do this in the IDE is up to you.
Working on a GUI in Eclipse using WindowBuilder and ran into a roadblock..
I've created a JWindow with a drop-down box intended to display a list of people from a people array. The structure of my classes are:
public class Person {
String name;
int age;
ArrayList<Goal> goals;
}
public class Goal {
String name;
int daysToComplete;
}
Within this JWindow GUI, the drop-down box lists out all of the Person instances. Once I select a person (let's say Bob) - I want to dynamically create labels and JTextAreas to list out Bob's attribute values, for example:
Name: Bob
Age: 20
Goals:
- Goal 1, complete in X days
- Goal 2, complete in Y days
and so on.. I don't want to statically add 3 labels (Name, Age, Goals) and their respective JTextAreas (Bob, 20, Goal 1/Goal 2), because the structure of Person will likely change in the future.
What is the best way to do this?
Thanks!
If I'm understanding you correctly, you can get what you want by creating anonymous instances of JLabel and JTextArea and placing them into an array list. I don't know the specifics of your environment, but hopefully, you can follow the idea:
ArrayList<JLabel> nameLabelList = new ArrayList<JLabel>();
ArrayList<JLabel> ageLabelList = new ArrayList<JLabel>();
ArrayList<Goal> goalList = new ArrayList<Goal>();
// Event handler method
public void personSelected(person)
{
nameLabelList.add(person.name);
ageLabelList.add(person.age);
// This assumes each person has a single goal. You can adapt the code
// for multiple goals easily
goalLabelList.add(person.goal);
}
Then, after the lists are created, all you have to do is loop through these array lists and spit them out into your UI:
for(int counter = 0; counter < nameLabelList.size; counter++)
{
myContainer.add(nameLabelList.get(counter));
myContainer.add(ageLabelList.get(counter));
myContainer.add(new JLabel(goalList.get(counter).toString()));
}
After adding the contents of the array lists, make sure that they show up in the UI:
myContainer.revalidate();
myContainter.repaint();
You will have to add new Panels to your Main Panel. So your Main Panel should provide a scrollable inner Panel to which you add new lines. If you have ever worked with HTML and Tables you will understand what I am talking about.
Once you got this attribute-show-panel (inner Panel), you can load as many attributes into it with a for loop as you want.
The code would technically be like for each goal in goalArray -> add new linePanel to attribute-show-panel.
whereas a linePanel yould store a label, abutton, etc and many line Panels would list vertically
I have the following class ReviewPanel in which i have created a JList and trying to populate it with Vector passed to it. the vector already has its values filled but when i add it to JList it doesn't shows anything.
following is my class
public class ReviewPanel extends JPanel
{
private Vector bookList;
private JList jl;
private JRadioButton poor,fair,avg,good,exlnt;
private JButton jb;
public ReviewPanel(Vector bookList)
{
this.bookList = bookList;
jl = new JList<String>(this.bookList);
String tmp=null;
for(int i=0;i<bookList.size();i++){
tmp = tmp + bookList.get(i) + "\n";
System.out.println(tmp); //here it is showing the values in booklist vector
}
add(jl);
ButtonGroup bg =new ButtonGroup();
poor = new JRadioButton("1 Poor");
fair = new JRadioButton("2 Fair");
avg = new JRadioButton("3 Average");
good = new JRadioButton("4 Good");
exlnt = new JRadioButton("5 Excellent");
bg.add(poor);
bg.add(fair);
bg.add(avg);
bg.add(good);
bg.add(exlnt);
add(poor);
add(fair);
add(avg);
add(good);
add(exlnt);
jb = new JButton("Submit Review");
add(jb);
}
//more code
}
below is the pic for what it looks like. even though i have added the Jlist already. it doesn't show anything
not savvy to jlist and vectors, any help appreciated.
In the past I have had simular issues with the FlowLayout, which is the default layout for a JPanel.
It sometimes does not show one of the items added (in my case it was often the last).
You can test if the use of your layout manager is your problem by starting you function with setLayoutManager(null). This turns is off, which will place the elements on their default locations and sizes. If the JList does show this is your problem.
A very good example for your program is the Button Demo. This also shows the use of SwingUtils to make sure you create your program on the 'Event Dispatch Thread', which is required for all interaction with Swing objects.
I'm trying to create a Java GUI dynamically by taking values from a result set and using it to generate a checklist. I've created a small demo program to demonstrate what I've done:
SQL Commands
CREATE USER 'test'#'localhost' IDENTIFIED BY 'testpw';
CREATE DATABASE combotest;
USE combotest;
CREATE TABLE combotable (
id INT(5) NOT NULL PRIMARY KEY auto_increment,
type VARCHAR(50) NOT NULL);
INSERT INTO combotable (id, type) VALUES
(default, 'Label'),
(default, 'Textfield'),
(default, 'Combo'),
(default, 'Label'),
(default, 'Textfield'),
(default, 'Combo'),
(default, 'Combo');
GRANT SELECT ON combotest.* TO 'test'#'localhost';
For your convenience if you'd like to test it yourself I've put all the SQL commands above.
Now, for my Java code:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.*;
import javax.swing.*;
public class resToComboDemo implements ActionListener {
//JDBC Variables
static Connection connect = null;
static Statement statement = null;
static ResultSet res = null;
#SuppressWarnings("rawtypes")
//Other Variables
JComboBox comboBox;
JButton submit;
JFrame frame;
JLabel label;
JTextField textField;
Container pane;
public static void main(String[] args) throws SQLException {
new resToComboDemo();
}
public resToComboDemo() throws SQLException {
try {
Class.forName("com.mysql.jdbc.Driver");
// Setup the connection with the DB
connect = DriverManager
.getConnection("jdbc:mysql://localhost/combotest?"
+ "user=test&password=testpw");
statement = connect.createStatement();
//Note: in this specific case I do realize that "order by id" is not necessary. I want it there, though.
res = statement.executeQuery("SELECT * FROM combotable ORDER BY id");
createStuff(res);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "Error 1: "+e, "Error!", JOptionPane.ERROR_MESSAGE);
} finally {
connect.close();
}
}
#SuppressWarnings({"rawtypes", "unchecked" })
public void createStuff (ResultSet res) throws SQLException {
frame = new JFrame("Testing dynamic gui");
Dimension sD = Toolkit.getDefaultToolkit().getScreenSize();
int width = sD.width;
int height = sD.height - 45;
frame.setSize(width,height);
pane = frame.getContentPane();
pane.setLayout(new GridLayout(0, 2));
while (res.next()) {
Object[] options = { "Pass", "Fail"};
String type = res.getString("type");
JLabel label = new JLabel("<html><small>"+type+"</small></html>");
JLabel blank = new JLabel(" ");
blank.setBackground(Color.black);
blank.setOpaque(true);
if (type.equals("Label")) {
label.setBackground(Color.black);
label.setForeground(Color.white);
label.setOpaque(true);
pane.add(label);
pane.add(blank);
} else if (type.equals("Combo")) {
pane.add(label);
comboBox = new JComboBox(options);
pane.add(comboBox);
} else if (type.equals("Textfield")) {
pane.add(label);
textField = new JTextField(20);
pane.add(textField);
}
}
JLabel blank2 = new JLabel(" ");
pane.add(blank2);
submit = new JButton("Submit");
submit.addActionListener(this);
pane.add(submit);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
Now, everything works great with creating the GUI here. However, I need to be able to treat the Combobox and Textfield components as their own separate entities. Meaning, I want to be able to get user input from each different component. Right now, if I were to request information from textfield, it just gives me the information from the last textfield. This makes perfect since, because that's how java reads it. I have no problem with that.
I just can't for the life of me figure out how to get each component's input separately. Perhaps by taking the result set and adding the results to some type of array? I've attempted this multiple times in different flavors and I can't get it to come out the way I need it to. Some of you are going to request that I show you what I've tried... but honestly, it's not worth it.
And, before anybody asks: No, I will not use FlowLayout. :)
Any help is greatly appreciated!
There are probably a few ways to achieve this based on what you want to do...
If you are only performing a batch update, you could use a Map keyed to the id of the row and mapping to the Component.
This way, when you want to save the values back to the database, you would simply iterate the Maps key values, extract the Component associated with each key and then extract the value of the Component...
I might consider making a wrapper interface which has a simple getText method and wrap the component within it, making the implementation of the wrapper responsible for extracting the text, but that's just me ;)
If you want to perform updates when a individual component is updated, you would need to swap the mapping, so that the Component would the key and the id would be mapped to it.
This would mean that when some kind of event occurred that would trigger and update (ie a ActionEvent), you could extract the source from the event and look up the id in the Map based on the Component that caused the event...
Now...frankly, I would simply use a JTable and create a custom TableModel which could model all this.
This would require you to create POJO of the table, maintaining the id, type and value within a single object. This would define a basic row in the table.
The only problem is you would need to create a (reasonably) complex TableCellEditor that could take the type and return an appropriate editor for the table. Not impossible, it's just an additional complexity beyond the normal usage of a table.
This would all the information you need is available in a single object of a single row in the table.
Take a look at How to use tables for more details
Equally, you could use a similarly idea with the Map ideas above...
You could also simply create a self contained "editor" (extending from something like JPanel), which maintain information about the id and type and from which you could extract the value and simply keep a list of these....for example...
what about interrogating the Container ( pane) which contains the components
getComponents() method and loop through the sub component and check for JComobox and JTextField do the required cast and retrieve the value
Just an idea in case you are against adding the sub-components into a kind of list
You only have a reference to the last text field or combo box that you create, since you are reusing the variables that hold them. I would put them in an ArrayList, store each new text field and combbox as you create them, then you can go back and get input from all of them after you're done.
---------- (after the OP's response to the above paragraph)
No, there is no "place to refer you" -- it's your set of requirements, it would be pretty remarkable to find code that already existed that did this exact thing. Java and Swing give you the tools, you need to put things together yourself.
You don't show your "actionPerformed" routine, but let's hypothesize about it for a minute. It is called by the framework when an action is done, and it is passed an "ActionEvent" object. Looking through its methods, we find that it has "getSource()", so it will give you a reference to the component which generated the event.
Let's further think about what we have -- a set of components in the UI, and ones which can generate events are interesting to us. We want to, in this case, retrieve something from the component that generated the event.
If we have the component (from actionEvent.getSource()) and we want to do something with it, then we can, at worst do something like the following in the actionPerformed() method:
Component sourceComponent = actionEvent.getSource();
if (sourceComponent instanceof JComboBox)
{ JComboBox sourceBox = (JComboBox) sourceComponent;
// get the value from the combo box here
}
else if (sourceComponent instanceof JTextField)
{ JTextField sourceTextField = (JTextField) sourceComponent;
// get the value from the text field here
}
// or else do nothing -- our action was not one of these.
Done this way, you don't even need to keep a list of the components -- the UI is keeping a reference to all of them, and you just use that reference when the actionEvent occurs.
Now, this is not the only or even the best or the simplest way of doing this. If you wanted to extend JComboBox and JTextField with your own classes, you could have those classes both implement an interface that defined something like getValue() or getText; then you would not need the ugly instance of operator, which can usually be done away with by better design and planning.
I am learning Java with Swing and I have some problems with using JTextField. In my program I want to dynamically add a few JTextFields with some text:
while( (ln = bufFile.readLine()) != null ) {
// inIdPanel is JPanel
inIdPanel.add(new JTextField(ln));
}
And it works good. However, the content of these JTextFields can be modified by users, and later I want to call getText() from all of them. Is this possible? How can I do this?
I saw this question: Java Swing: JButton creates new JTextField(s) but this isn't enough to solve my problem (I think using arrays in my case is not a good idea but maybe I'm wrong).
The reason why you cannot call getText() is that you have not stored a reference to the JTextField when you created it. You will need to use an array or collection to store the JtextFields as you create them so you can call the method on them later. A collection will be easier than an array because you do not know how many lines you will read in so you want it to be able to grow.
List<JTextField> fields = new ArrayList<JTTextField>();
while( (ln = bufFile.readLine()) != null ) {
JTextField field = new JTextField(ln);
inIdPanel.add(field);
fields.add(field);
}
Then you can call the .getText() from all of them
for(JTextField field: fields){
System.out.println(field.getText());
}
For an easy solution, just add an ArrayList<JTextField> textFieldList and add to the code you posted:
while((ln = bufFile.readLine()) != null) {
textFieldList.add(new JTextField(ln));
inIdPanel.add(textFieldList.get(textFieldList.size()-1));
}
Then, when you want to access the text fields, you simply iterate through them, e.g.
for (JTextField jtf : textFieldList) {
/* Operate on jtf, call methods, etc */
}
You could replace the ArrayList with an array if there is a defined limit on how many text fields you could add, but the list is nice if that quantity is unknown.