For some reason, I can't add anything to my JList. The JList is visible but simply shows white - nothing can be selected.
List list;
DefaultListModel listModel;
//...
list = new JList();
list.setBounds(220,20,150,200);
listModel = new DefaultListModel();
listModel.addElement("ONE");
panel.add(list);
Am I missing something?
The JList is not using the listModel.
One way is to initialize the JList by specifying a ListModel to use:
DefaultListModel listModel = ...
JList list = new JList(listModel);
Then, performing changes to the listModel (such as calling addElement) will cause the changes to appear on the JList.
For more information on using JLists, the How to Use Lists lesson from The Java Tutorials is a good source.
You never set the list's model to the ListModel you've constructed.
Related
I have two datatemplates. One is the default and the other one is for when the user selects this item. I need to give the selected item double width and height of the normal template. How can I do this?
What you want to do is not difficult, but it is not solved by swapping the data template. Instead, it is accomplished by using Visual States in XAML. A Visual State allows you to create multiple "views" of your XAML (for example, what it looks like when it is selected and when it is not selected) and to switch between those easily. Swapping data templates is a big deal, Mostafa, and can result in your UI flickering because the underlying subsystem has to re-render so many parts of the visual tree.
If you want to learn more about the Visual States, you might read over the blog article I wrote on the same subject.
http://blog.jerrynixon.com/2013/11/windows-81-how-to-use-visual-states-in.html
The only problem now is to figure out how to trigger the visual state when the item in a gridview or listview is selected. First, you should know that IsSelected is a property on the gridviewitem or listviewitem control that houses your item. However, it's tricky to reach that property and the most common approach is to sub-class your gridview/listview and override PrepareContainerForItemOverride and set the binding in code-behind.
Like this:
class MyModel
{
public bool IsSelected { get; set; }
}
class MyList : Windows.UI.Xaml.Controls.ListView
{
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
var model = item as MyModel;
var listViewItem = element as Windows.UI.Xaml.Controls.ListViewItem;
var binding = new Windows.UI.Xaml.Data.Binding
{
Source = model,
Mode = Windows.UI.Xaml.Data.BindingMode.TwoWay,
Path = new PropertyPath(nameof(model.IsSelected)),
};
listViewItem.SetBinding(Windows.UI.Xaml.Controls.ListViewItem.IsSelectedProperty, binding);
base.PrepareContainerForItemOverride(element, item);
}
}
I hope this helps.
Best of luck!
I have couple of dropdownlist controls, that shares the same dataprovider(same reference).
I had overridden the set dataprovider method for a sort function.(code below). The issue is that, when I set this shared dataprovider to a new dropdownlist, all the existing dropdown contorls sharing the dataprvider gets unselected(loses its previously selected values).
override public function set dataProvider(value:IList):void{
if(value is ArrayCollection){
var sort:Sort=new Sort();
var sortField:SortField = new SortField();
sortField.numeric=false;
sort.fields=[sortField];
ArrayCollection(value).sort=sort;
ArrayCollection(value).refresh();
}
super.dataProvider=value;
}
There are a ton of isues sharing the dataProvider between components. We've run into this with a lot of clients using our AutoCompleteComboBox.
You can easily use the same source, but a different--separate--collection for each of your dataProviders.
var dataProvider1 :ArrayCollection = new ArrayCollection(someArray);
var dataProvider2 :ArrayCollection = new ArrayCollection(someArray);
var dataProvider3 :ArrayCollection = new ArrayCollection(someArray);
Each collection is just a wrapper around the base source. Sorting one will not affect any of the others, leaving your other ComboBoxes or DropDownLists untouched.
I did no research on this, but there are two issues/ideas coming up:
if you literally use the same reference to the same arraycollection, you do not need to sort this array more than once (and you actually do this by assigning the same arraycollection more than once)
if it about only single-selection dropdowns, then there is a simple solution:
var oldSelected : TypeOfItem = selectedItem as TypeOfItem;
// do the sort (like in your code)
super.dataProvider=value;
selectedIndex = getItemIndex(oldSelected);
I use a Label component to display the length of an ArrayCollection. How do I get it to update when I add new items to the collection?
Here's the text field for the Label:
text="{model.meetingInfo.documentList.length}"
Here's the handler for adding a new item to the collection:
var attachmentProgressVO:AttachmentProgressVO = new AttachmentProgressVO();
attachmentProgressVO.fileReference = file as File;
newAttachmentList.addItem(attachmentProgressVO);
checkIfUpdate(file as File, attachmentProgressVO);
meetingInfo.docsAndAttachmentsList.addItem(attachmentProgressVO);
I tried adding these 2 lines but that didn't work:
meetingInfo.docsAndAttachmentsList.itemUpdated( attachmentProgressVO );
meetingInfo.docsAndAttachmentsList.refresh();
I also tried changing this:
public var docsAndAttachmentsList:ArrayCollection = new ArrayCollection();
to this:
private var _docsAndAttachmentsList:ArrayCollection = new ArrayCollection();
..with a getter and setter but that didn't work.
I'm not using the right approach, am I?
Generically, Binding only looks at a specific object; you can't drill down 4 objects deep to a specific property and expect binding to update values.
Changing the documentList does not change meetingInfo or Model, so binding will never be triggered. itemUpdated() and refresh() should update the list based class which displays the data; but will not affect your label displaying the count.
You need to listen on the collection for a collectionChange event and manually update the label's text in the collectionChange handler.
A question about ItemRenderers: let's say I have an ArrayCollection that is my application data sitting inside a global object. I them populate a sparks list with this data, setting the ArrayCollection as the dataProvider.
So each ItemRenderer gets a copy of an item sitting in the array. You can override the "set data" method to set the data something more domain-specific. The problem is that the data is a copy of the original item.
Now let's say we want to add some data to the item while inside the ItemRender. For example, it could call a method on the item telling it to load some details about itself, or maybe we allow the user to modify something on the item.
Obviously, we can't do any of this if we are operating on a copy because it will be thrown away as soon as the ItemRenderer is destroyed and the original object doesn't know anything about what happened.
So what's the best practice? Should I just use the itemIndex of the renderer to pull out the original item from my global array like this:
{globalArrayCollection}.getItemAt(this.itemIndex)
But it seems kind of clunky to me. Is there a best practice for dealing with this?
Not sure I'm following but it sounds like you're looking for a way to get at your item renderer to set/change a value.
You could go about accessing a method on the renderer directly.
In your renderer:
public function setSomeValue(aValue:String):void{
someString = aValue;
}
You would also set the data on your ArrayCollection as well.
To access this method you would use this:
var dataGroup:DataGroup = list.dataGroup;
var itemRenderer:YourItemRenderer = dataGroup.getElementAt(list.selectedIndex) as YourItemRenderer;
itemRenderer.setSomeValue("string");
Hmm, why do you think that original ArrayCollection won't change if you change values in itemRenderer? For me this works and initial ArrayCollection changes.
[Bindable]
protected var model:Model;
override public function set data(value:Object):void
{
super.data = value;
this.model = value as Model;
}
protected function changeValue():void
{
model.value = "newValue";
}
Or am I misunderstood something?
I am having an issue in my Swing app where I am creating a simple JList by passing it a model - and even though the model is demonstrably populated, the JList refuses to display it's own model's contents.
DefaultListModel dlm = new DefaultListModel();
String[] modelElems = {"Apple", "Orange", "Banana"};
for(int i = 0; i < modelElems.length; i++)
dlm.add(i, modelElems[i]);
JList lstFruitList = new JList(dlm);
lstFruitList.setVisible(true);
When my Swing app runs, I see the JList on screen, but it is completely empty! I've looked at countless examples, poured over the Swing tutorials, and cannot seem to figure out what is going on. Anybody ever had this happen to them before?!? Anything that is glaringly-obviously-wrong?!?
NOTE:
The following print statement indeed shows that my model has 3 elements:
// Prints "Fruit List model has a size of 3"
System.out.println("Fruit List model has a size of " + dlm.size());
However, if I try to loop through and print the names of the fruits in my model, by calling (String)dlm.get(i) at every iteration (where i is the iteration var), it prints each model element as null...
hmmmm
That code works fine for me. Some thoughts:
I see that you call the setVisible on the JList, how exactly are you adding it to whatever you are displaying?
Are you adding the elements after you display your JFrame? If I remember correctly, that won't work well, I think you have to repaint everything.
Make sure that you're not messing around with the list model at some point; Maybe at some point later in the code, you're changing it?
Ensure that you are actually looking at the right element; maybe your list is hidden behind something else?(try setting the background color, i.e. lstFruitList.setBackground(Color.BLUE);
Final thought, are you sure that you've compiled it properly? I've sometimes accidentally forgotten to compile, or had messed up something and was running an older version of the code and was confused as to why something didn't work.
For reference, here's the code that I ran:
import java.awt.*;
import javax.swing.*;
public class javatest{
public static void main(String[] args){
JFrame f = new JFrame("HELLO");
DefaultListModel dlm = new DefaultListModel();
String[] modelElems = {"Apple", "Orange", "Banana"};
for(int i = 0; i < modelElems.length; i++)
dlm.add(i, modelElems[i]);
JList lstFruitList = new JList(dlm);
lstFruitList.setVisible(true);
JPanel p = new JPanel();
p.add( lstFruitList );
f.add( p );
f.setLocation(0,0);
f.setSize(400,400);
f.setVisible(true);
}
}