• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

JList set element visible

 
Ranch Hand
Posts: 39
Netbeans IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
First, let me describe a couple of restrictions that I have in my environment and the problem that I'm having. So first the restrictions, I'm working on an airgapped environment so everything here has to be hand jammed in by me. There is no way for me to just copy paste my working code in so there may be little typos here and there. Second some of the systems that I'm running this one are fairly archaic, so the newest version of java that I'm using is 1.4 and it's not possible for me to put in backports of new java apis.

Now for the problem, I'll post the code below this description. I'm making a gui frontend that has a JList in a tabbed pane and another pane that contains a list of buttons. I want these buttons to act like filters so that when they are pressed the jlist only shows items related to that button. I need to maintain the integrity of the elements in the background so that I can set them to visible and invisible at will. I've thought about extending the buttons and backing them with the list, but that's pretty computationally expensive to do every time there is an update. Anyway, here's some code.



The above code is about as complete as I care to make it, there are a couple other things in there, but it's mostly visible niceties. Things like setting fonts, manage sound events and the like.
The next code are the helper classes, they're the ListItem object and the TextRenderer.

 
Bartender
Posts: 5167
11
Netbeans IDE Opera Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
That's a lot of code to go through, so I didn't.

Charles Burton wrote:I want these buttons to act like filters so that when they are pressed the jlist only shows items related to that button.


Have you considered using a single column JTable with a RowFilter?
 
Ranch Hand
Posts: 4632
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
> I want these buttons to act like filters so that when they are pressed the jlist only shows items related to that button.

when the program starts create listModels for all the buttons, and an 'overall' listModel. Jlist opens with 'overall' model.
whatever a button is clicked, it sets the model of the JList to the model relative to that button clicked.
 
Charles Burton
Ranch Hand
Posts: 39
Netbeans IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Darryl Burke wrote:That's a lot of code to go through, so I didn't.

Charles Burton wrote:I want these buttons to act like filters so that when they are pressed the jlist only shows items related to that button.


Have you considered using a single column JTable with a RowFilter?



I did think of that actually the problem is that RowFilter is a Java 6 thing, and I have to work with the lowest common version which is 1.4. Thanks for the reply though!
 
Charles Burton
Ranch Hand
Posts: 39
Netbeans IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Michael Dunn wrote:> I want these buttons to act like filters so that when they are pressed the jlist only shows items related to that button.

when the program starts create listModels for all the buttons, and an 'overall' listModel. Jlist opens with 'overall' model.
whatever a button is clicked, it sets the model of the JList to the model relative to that button clicked.



I did think about that, so do you think the best way would be to extend JButton and then use that model as the internal tracker for what to render? Also, I would just have to call repaint() on the JList and it would draw it with the new information whenever I set the model from the button right?
 
Charles Burton
Ranch Hand
Posts: 39
Netbeans IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Also, if I do use the model backed buttons. Just for advice, would it make more sense to have a model that contains all the messages when I want to show all of them or would it be better to just go through the buttons and construct one on the fly from the values contained in each?
 
Darryl Burke
Bartender
Posts: 5167
11
Netbeans IDE Opera Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Charles Burton wrote:the problem is that RowFilter is a Java 6 thing, and I have to work with the lowest common version which is 1.4.


Ah, right, you did say that. Sorry. My only excuse is that I learned Java after 1.6 was out, so I'''m not very conscious about what Java 5 and 6 added.

Charles Burton wrote:do you think the best way would be to extend JButton and then use that model as the internal tracker for what to render? Also, I would just have to call repaint() on the JList and it would draw it with the new information whenever I set the model from the button right?


I wouldn't extend JButton, since you're not looking for a specialized JButton class. Instead I might create a class that holds a JButton and a ListModel and takes a JList as a constructor parameter, among others. The class should have a method to return the JButton so that it can be added to the GUI, and should set its ListModel to the JList in an ActionListener#actionPerformed(...) added to the button.

And repaint() is already triggered after setModel(...), so there's no need to call it yourself. setModel(...) fires a propertyChange ("model", ...) and the UI delegate responds to that by (among other work) calling its redrawList() method which calls revalidate() and repaint() on the JList.
 
Darryl Burke
Bartender
Posts: 5167
11
Netbeans IDE Opera Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Charles Burton wrote:Also, if I do use the model backed buttons. Just for advice, would it make more sense to have a model that contains all the messages when I want to show all of them or would it be better to just go through the buttons and construct one on the fly from the values contained in each?


Either way, you duplicate the data structures that hold the list elements in the individual and 'master' model. I would try aggregating the individual models in a custom multi model, something like (entirely untested, may have discrepancies in indax calculation, and would be much easier/better with Java 5 features - varargs and Generics)If the number of contained models is large, and each is unchanged during the life of the multi model, it may be better to cache the (total) size in a field each time a model is added or removed.

I haven't thought about what issues could arise out of changing the content of the contained models. Probably could be handled by chaining the property changes triggered.
 
Charles Burton
Ranch Hand
Posts: 39
Netbeans IDE Java Linux
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
So, I like the idea of the custom list model. It's not something that I had thought of before, but I think that I can simplify it a little by merely filtering the returned results. So, the buttons are stored in a hashmap that it keyed to their name. I'm going to build a custom list model that filters the results based on that source ID from the hashmap. I'll post code in a little bit when I get it done.
 
Charles Burton
Ranch Hand
Posts: 39
Netbeans IDE Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
So, here's the code from my FilteredListModel, I've tried to keep the data duplication to a minimum and made the code as simple to read as I can. My code is fairly specialized in that it sets and returns based on ListItems, however it's pretty easy to modify so that it uses POJOs. I'm going to test it for a couple of days, but so far so good! BTW I meant to say hadn't on the thought about the AbstractListModel, I hadn't thought of that. It even provides de-duplication based on orginating source and a percentage of the difference between two items. There is one little bug that I found and I'm not sure how to fix it, but whenever you set a filter it does work. The list shows only the filtered results, however if a new item is added from another update, that one shows up in the filtered results.



Please, any suggestions would be appreciated.

 
Darryl Burke
Bartender
Posts: 5167
11
Netbeans IDE Opera Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
A few thoughts, on glancing through the code. Not all of them may be relevant.
  • I see some unnecessary casting to ListItem. For example, in the getElementAt(int) implementation; the method is defined to return Object so there's no need to cast the returned value.
  • Maybe, just maybe, you could avoid duplication of items by using a Set as the backing data and overriding equals(...) [and hashCode()] in the ListItem class to return true when the difference is within diffThresh. That's provided you don't need any other interpretation of equality elsewhere.
  • Thinking on the same lines, I'm concerned about what happens when you abort adding an item as it is perceived as a duplicate, and the item it duplicates is then removed. But maybe your use case requires that such item no longer appear in the list.
  • If however you do need one item to be retained after an aborted add(...) followed by a remove(...) of the item that caused the add(...) to abort, then I would suggest using a Map(ListItem, Integer) where each item is mapped to the count of how many times it has been added; decrement in remove(...) and remove the key when it maps to 0.
  • Have you considered extending ArrayList (or a Set or Map implementation if either of those suggestions makes sense) to do the heavy lifting, and using that for the backing data in a relatively simple AbstractListModel subclass?
  • Either way, I feel an empty filter String should result in the filtered list containing all items, obviating the need to test if (filter.equals("")) anywhere. But that's just a feeling.
  •  
    Darryl Burke
    Bartender
    Posts: 5167
    11
    Netbeans IDE Opera Java
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    if a new item is added from another update, that one shows up in the filtered results.


    You have a filteredList.add(li); that is unconditionally executed when filter is not the empty String (line 37). That should probably be wrapped in the same condition you use in setFilter(...) -- if (filter.equals(li.getSource())
     
    Charles Burton
    Ranch Hand
    Posts: 39
    Netbeans IDE Java Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    You're definitely correct about the unnecessary casting to ListItem, I actually only had a short little while to throw this together and run an overnight profile on it. I'm not sure if you're familiar with the Dice algorithm, but when I'm doing the de-duplication of the items contained in the list it's a percentage based differece. The way it works is I take the tracker line from each ListItem with the same number of lines and the same originating source and first compare them to see if they're equal, failing that it runs through the dice. I tried to make sure that the algorithm is run as little as possible. Anyway the way it flows is that once it fails all the original tests meaning it has the same originating source, the same number of lines, and is not equal I dice it. What happens when it gets diced is each string is broken down into a set of bigrams, I compare the two sets of bigrams and then calculate a difference in the tracker based on a percentage. The math for the computation is double finalNum = (2 * totalbigrams)/(nx.size() + ny.size();. I also don't abort adding a new item, it just removes all the previous examples that are within that threshold allowance. If you look at lines 32 and 33 you'll see that after I have removed all previous examples of this message I unconditionally add it. There is no need to maintain previously added ListItems because this is merely notification, the messages are added to the database already and kept no matter if they are cleared in the message window. I didn't post the methods here, but there's actually buttons to adjust the threshold of the dice algorithm up and down.

    You have a filteredList.add(li); that is unconditionally executed when filter is not the empty String (line 37). That should probably be wrapped in the same condition you use in setFilter(...) -- if (filter.equals(li.getSource())


    Excellent catch, thank you.

    I would like to thank you as well, you've been very very helpful.
     
    Charles Burton
    Ranch Hand
    Posts: 39
    Netbeans IDE Java Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Oh, and I like your mention of using a set to back the ListModel with. I had thought of that, but because the ListItem value variable will always be different due to timestamps embedded in the string the objects will always be different. They're also embedded at the client side and applied whenever they're generated so I can't really move them to after the de-duplication portion either.
     
    Charles Burton
    Ranch Hand
    Posts: 39
    Netbeans IDE Java Linux
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    So here's the updated code taking into account all of Darryl's suggestions that I could.

     
    Darryl Burke
    Bartender
    Posts: 5167
    11
    Netbeans IDE Opera Java
    • Likes 1
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    I'm not sure if you're familiar with the Dice algorithm


    Never heard of it, actually (I'm not a programmer). Is it what Wikipedia refers to as Dice's coefficient? http://en.wikipedia.org/wiki/Dice's_coefficient If so, it's beyond me

    Most Dice-related questions on programming forums involve Random#nextInt(6)

    I would like to thank you as well, you've been very very helpful.


    You're welcome; it's a pleasure to be able respond to an actual programming question that isn't homework. There's all too few of those.

    And thank you for sharing the code on the forum. It's sure to be an eye-opener for people who could have use of a custom ListModel and come across this thread.
    reply
      Bookmark Topic Watch Topic
    • New Topic