I have created a client -> server chat room system, and I have a list of currently connected users, which is currently displayed on a button click within a JTextField, this currently works fine and displays the string array. However, I have added another component to my GUI, being a JList. I have been trying to create a method called updateUserList to update the JList with the users that are connected. I have tried to use a DefaultListModel of type String, however this displays nothing in the JList and I am unsure as to why.
Below is the updateUserList method I have created:
public void updateUserList()
{
model = new DefaultListModel<String>();
for(String usernames : users)
model.addElement(usernames);
jl_users = new JList<String>(model);
}
Please note that model, usernames and jl_users are defined globally, therefore I have not included them in the post.
Why are you using DefaultListModel?
If you want a simply List just use it like this
public void updateUserList()
{
jl_users = new JList<String>(users.toArray(new String[users.size()]));
}
or straight forward
jl_users = new JList(users.toArray());
Related
I am currently developing a javafx desktop application. It contains two observableList<Item>s and two HashMap<String,Double>s. I am currently develop the menuBar , which contains these menuItem s, i.e. Open, New, Save and Save As.
Consider the case where I have started the desktop application and added a few Item to the observableList<Item>. Then all of a sudden, I want to hit any one of the menuItems listed above. First thing I want to check in my program is whether the current workflow needs to be saved before proceeding to start a new workflow (New menuitem).
I have the following method in place at the moment but I think it looks very clumsy and inefficient.
The method I developed is to set a variable private static final boolean isSaved = false;
And then within the two observableLists, I added a Listener to them:
obslist1.addListener(new ListChangeListener<Item>(){
#Override
public void onChanged(ListChangeListener.Change change) {
isSaved = false;
}
});
The code for obslist2 is identical. And the isSaved variable is set to true only if the user actually presses the Save or Save As menuItem.
I find my method very clumsy and inefficient. Is there a better way to do this?
You can do something like
BooleanProperty saved = new SimpleBooleanProperty();
InvalidationListener savedListener = obs -> saved.set(false);
and then
private void save() {
// save the data...
// mark data as saved:
saved.set(true);
}
with
obslist1.addListener(savedListener);
obslist2.addListener(savedListener);
anythingElseThatMightChangeAndIsImportant.addListener(savedListener);
Your save button and menu item, etc can do
saveButton.disableProperty().bind(saved);
I'm having trouble adding items to a JList called lstContacts whenever a button is pressed.
When I press my new contact button, a line should be added to lstContacts but when I press the button nothing happens.
Here is my action listener for the new contact button:
newContactButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Contacts contacts = new Contacts();
contacts.createContact();
}
});
Here is my createContact method in the contacts class:
ArrayList<String> contactsList = new ArrayList<String>();
public void createContact() {
ContactsDB database = new ContactsDB();
System.out.println("new contact");
contactsList.add("New Contact");
listModel.addElement("New Contact");
}
And lastly here is my createCustomUIComponent() method:
private void createUIComponents() {
// TODO: place custom component creation code here
listModel = new DefaultListModel();
lstContacts = new JList<String>(listModel);
}
Why aren't the new contacts getting added to my JList?
The problem is here:
Contacts contacts = new Contacts();
contacts.createContact();
You are creating a new contacts object every time you click the button, but the JList doesn't have a reference to the Contacts object. I don't know how the contacts object is defined, but you should make sure that the object you are adding the contact to has reference to the DefaultListModel.
Another problem I see (but isn't causing the problem you posted about) is that you call new DefaultListModel(), but list model is a parameterized type. You probably want to call new DefaultListModel<String>().
Don't create an ArrayList of Contacts. All the Contact data should be stored in the ListModel.
So when you click on the button all you do is create a Contact and add the Contact to the DefaultListModel. However, your code doesn't make much sense because you're just creating an empty Contact. I would expect the Contact to have a name or something. So really what you want to do is have a text field were the user can enter a name and then when you click the button you create a Contact using the name data and then add the Contact to the list.
Read the section from the Swing tutorial on How to Use Lists. The ListDemo example show you how to dynamically add/remove an item from the DefaultListModel. Download the example and modify the working example to meet your specific requirements. When learning a new concept, start with working code.
First of all you have to have new a default ListView:
DefaultListModel listModel = new DefaultListModel();
Thenm build your JList with this list:
JList jList = new JList(listModel);
Anytime you want to change your list for each action you considered, call
addElement on your jList:
listModel.addElement("This is a test contact");
New to the forum and to Java. I am trying to have my JList respond when double-clicked, which I have accomplished. The JList is being populated by a SQL query which is ran when a button in the GUI is pressed. Based on the SQL query, the JList is populated, this is also working.
The issue comes about if I try to update the JList by clicking the button to query SQL again. When I click that, the change initially shows up in the JList, however when I click on that option in the JList it immediately switches back to what it was initially. When I double-click on what appears to be the incorrect name, the value that I have printing in the console reports correctly. So it has the value correct in the console but the rendering in the JList is not correct.
I appreciate any responses, I have combed the forums without any luck. I am new to Java so I'm sure there is quite a bit that isn't perfect with my code. Code is below please let me know if you need more. Thank you.
public JPanel results(StringBuilder message)
{
StringBuilder[] options = {message};
showOption = new JList(options);
showOption.setLocation(300, 50);
showOption.setSize(140,100);
showOption.setVisibleRowCount(10);
textPanel.add(showOption);
showOption.revalidate();
showOption.repaint();
MouseListener mouseListener = new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
//JList showOption = (JList) mouseEvent.getSource();
if (e.getClickCount() == 2) {
int index = showOption.locationToIndex(e.getPoint());
Object o = showOption.getModel().getElementAt(index);
System.out.println("Double-clicked on: " + o.toString());
}
}
};
showOption.addMouseListener(mouseListener);
return totalGUI;
}
public static void main ( String args[] )
{
//JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("[=] JTextField of Dreams [=]");
GUI_TextField demo = new GUI_TextField();
frame.setContentPane(demo.createContentPane());
//frame.setContentPane(demo.results(message));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(510, 400);
frame.setVisible(true);
}
Three things jump out at me immediately.
You're creating a new JList each time
You're manually setting the size and position of the JList
You're not removing the previous JList
For example...
public JPanel results(StringBuilder message)
{
StringBuilder[] options = {message};
// Create new JList
showOption = new JList(options);
// This is ill advised
showOption.setLocation(300, 50);
showOption.setSize(140,100);
showOption.setVisibleRowCount(10);
// What about the last JList?
textPanel.add(showOption);
This raises a number of possibilities, the likely one is that you are covering over the previous list, which is being brought to the front when textPanel is validated and painted.
Swing follows (loosly) the MVC paradigm (and for more details)
So instead of re-creating the view each time, you should simply re-create the model, for example...
public JPanel results(StringBuilder message)
{
DefaultListModel model = new DefaultListModel();
model.addElement(message);
showOption.setModel(model);
If showOption isn't created initially before this method is called, you should consider putting in a if statement to detect when showOption is null and initialise it appropriately.
You should also avoid using setLocation and setSize. Swing has being designed to operate with the use of layout managers, these make it possible to define workflow and general layout that can be used across multiple platforms.
Take a look at How to use lists and Laying Out Components Within a Container
I have a :
Client Class
ListView
TextField
I need to populate my ListView in order to form a table:
WORKING CODE:
clientModel = new LoadableDetachableModel() {
#Override
protected Object load() {
return Client.getClientListByCompanyName(searchClientInput.getValue());
}
};
searchClientInput.setModel(new Model<String>());
searchClientInput.add(new AjaxFormComponentUpdatingBehavior("onkeyup") {
#Override
protected void onUpdate(AjaxRequestTarget target) {
target.add(clientListViewContainer);
}
});
clientListView = new ListView<Client>(CLIENT_ROW_LIST_ID, clientModel) {
#Override
protected void populateItem(ListItem<Client> item) {
Client client = item.getModelObject();
item.add(new Label(CLIENT_ROW_COMPANY_CNPJ_ID, client.getCompanyName()));
item.add(new Label(CLIENT_ROW_COMPANY_NAME_ID, client.getCompanyCnpj()));
}
};
clientListViewContainer.setOutputMarkupId(true);
clientListViewContainer.add(clientListView);
add(clientListViewContainer);
Now, in my HTML, I have a TextField. Whenever an user types something in this TextField, a select will be made in the database with whatever he typed. So for each word, a select is made, and the table needs to be updated. I am guessing I will need to use AJAX and possibly a Model. I'm kind of lost about how I can do this, if someone can provide me examples I would be very grateful.
EDIT: New code that is throwing exception: Last cause: Attempt to set model object on null model of component: searchClientForm:searchClientInput
EDIT 2: Ok so the exception was that my TextField didn't had a model to bind data to. So what I did was: searchClientInput.setModel(new Model<String>());
I also had a problem with the event. Using onkeydown was working, but not as intended. I had Company Name 1-4. If I typed Company Name 1, I would need to press one key again so the table would get updated. With onkeyup this don't happens. Thanks for the help.
You could give the ListView a LoadableDetachableModel which provides the selected clients matching your TextField's value.
Use an AjaxFormComponentUpdatingBehavior on your TextField which add a parent of the ListView to the request target (don't forget #setOutputMarkupId().
I believe the best way to perform what you want (which is repainting a table/list at each input change --> DB access) is with a DataView and a DataProvider.
A DataView is just like the ListView component except it uses an IDataProvider to get the data you want to present. You are able to implement the DataProvider so it accesses your DB, and you can add restrictions (where clauses) to the DataProvider.
[this is more like pseudo-code]
public final class MyDataProvider<T> extends SortableDataProvider<T> {
// ...
Set filters;
// filters is the set where the restrictions you want to apply are stored
...
#Override
public Iterator<T> iterator(int first, int count) {
// DAO (Data Access Object) access to DB
// ...
return dao.findByRestrictions(filters).iterator();
}
...
}
Now on the ajax event on your input component you are able to update the filter being used in the DataProvider, and in the the next repaint of the DataView, the provider will "pull" the data matching the restrictions defined in the filter.
Hope it helps. Best regards.
In my current Apache Wicket project I have a search form for querying the database and displaying the query results in a ListView. The search input box is on the same page as the ListView with the results, and that ListView is filled with query results from a DAO, during invocation of the onSubmit() method of the form.
Everything works fine, but I need to display the number of search results. I tried to create a Label that is filled with the value of the size() method of the list got by the getList() method of the ListView instance, but no luck.
Thank you for any help in advance.
Depending on how you have built this form, you might only need to do label.setModelObject(listResults.size()). It's difficult to tell without seeing how are you doing it.
By what you're telling in your question, probably you're creating your Label like this new Label(labelId, listView.getList().size(). This won't work, you're setting the Label's Model at construction time with a constant value, that's the size of the list at construction time. You need to get that value inside a Model's getObject() to make the value "dynamic". Like, for instance,
AbstractReadOnlyModel sizeModel = new AbstractReadOnlyModel(){
public getObject(){
return listView.getList().getSize();
}
}
new Label(labelId, sizeModel);
With this, every time the page renders, sizeModel().getObejct() will be called to retrieve the value for the Label. In that other way, the Label has got a Model with a constant value.
You could even do label.setModelObject(list.size()) in the onSubmit() method.
From my ignorance on how you have built this form, I'll show you how would I do this. The List of results would be retrieved with a LoadableDetachableModel. That would be the Model of the ListView. Then, the Label can have for instance an AbstractReadOnlyModel that uses the ListViews modelObject to get its size.
public class MyForm extends Form {
private LoadableDetachableModel resultsModel;
private IModel searchModel;
public MyForm(){
searchModel = new Model();
TextField searchTextField = new TextField("search", searchModel);
resultsModel = new LoadableDetachableModel(){
protected Object load(){
return myService.get(searchModel.getModelObject());
}
}
ListView lv = new ListView("list", resultsModel){
// ...
}
Label resultsCount = new Label("count", new AbstractReadOnlyModel(){
public Object getObject(){
return ((List) resultsModel.getObject()).size();
}
})
SubmitButton button = new SubmitButton(){
public void onSubmit(){
//... No actions needed, really
}
}
// add's...
}
}
Using a LoadableDetachableModel for the ListView has the advantage of automatically detaching the Model, and therefore avoiding the whole List of results to get serialized into the Session.