I have a problem with my app which uses JavaFX... In one view I have a tableview which contains list of people and I want change row style one person. Here is my code:
personTable.setRowFactory(new Callback<TableView<Person>, TableRow<Person>>() {
#Override
public TableRow<Person> call(TableView<Person> personTableView) {
return new TableRowRightFormat();
}
});
...
private class TableRowRightFormat extends TableRow {
#Override
protected void updateItem(Object o, boolean b) {
super.updateItem(o, b);
if(o == null) {
return;
}
getStyleClass().remove("headPerson");
if(((Person)o).getId()==2) {
getStyleClass().add("headPerson");
}
}
}
And it is working for one person(id=2) but when I scroll up my table and when person with id=2 disappears another person with id!=2 gets style called 'headPerson' (always one Person on visible elements in tableview has style 'headPerson', but above code is executing once time). What is the problem?
Update: I tested your code on both JavaFX 2.2 and JDK 8 and it seemed to work fine for my simple test case. The logic seems right; the one thing you have to be really careful of in these types of style-class based cell and row implementations is making sure you don't add multiple copies of a given string to the list of style classes - in your implementation this looks right. Double check and make sure you have the strings exactly the same in the add(...) and remove(...) methods.
I like to completely bullet-proof these at a slight cost to performance:
private final String headPersonStyleClass = "headPerson" ;
private class TableRowRightFormat extends TableRow<Person> {
#Override
protected void updateItem(Person p, boolean b) {
super.updateItem(p, b);
ObservableList<String> styleClass = getStyleClass();
if (p != null && p.getId()==2 && (! styleClass.contains(headPersonStyleClass))) {
styleClass.add(headPersonStyleClass);
} else {
// remove all occurrences:
styleClass.removeAll(Collections.singleton(headPersonStyleClass));
}
}
}
If you are using JavaFX 8, a better approach is to use a PseudoClass for this.
Related
I have two combo-boxes as below,
whenever i click done button, i get the values from combo-box and store it in a object like below,
public class comboValues{
private String label1ComboString;
private String label2ComboString;
public String setLabel1Combo(String val){
this.label1ComboString = val;
}
public String setLabel2Combo(String val){
this.label2ComboString = val;
}
public void getLabel1Combo(){
return this.label1ComboString;
}
public void getLabel2Combo(){
return this.label2ComboString;
}
}
in a controller class i use,
comboValues obj = new comboValues();
obj.setLabel1Combo(label1ComboBox.getSelectionModel().getSelectedItem());
obj.setLabel2Combo(label2ComboBox.getSelectionModel().getSelectedItem());
For a design with two combo box the code looks simple. My doubt is what if the number of combo-boxes increases? with the above approach code will have
lot of lines. What is the design to overcome this problem and how can i implement that to this scenario?
You can have an array or an ArrayList of ComboBoxes. This way you can reference an arbitrary number of boxes. Your class would change to something like this:
public class ComboValues {
private String[] comboStrings;
...
public void setComboLabel(String label, int comboNum) {
comboStrings[comboNum] = label;
}
public void getComboLabel(int comboNum) {
return comboStrings[comboNum];
}
public void getComboBoxCount() {
return comboStrings.length;
}
}
...
String[] labels = ...
for (int i = 0; i < obj.getComboBoxCount(); i++) {
obj.setComboLabel(labels[i], i);
}
I can see from your approach that you want to add more combo-boxs and against it you want to do less code in java to handle those all.
You have option of implementing Array List collection and store multiple combo boxes inside this. so every time you will not be needed to create new object and it will become dynamic.
Hope it will clear your doubt. If you have not cleared please comment.
My question is conceptual about synchronizing data and events in programming a gui. (This example shows batch state being the facilitator of taking classes that implement the same interface and dynamical updating cells in two different frames.This code is where I got my idea. )
I am assuming that I will create new instances of this batch state object specifically in the classes where an event is triggered(panel) and the reaction to that event(another panel) . I will do this by adding the classes that need to communicate to the a list of bsListeners. Then call the batch state function like "setSelectedCell()" to iterate over each class to synchronize them.
The Problem
This would work perfect if the object both shared the same arrayList but since they are both new instances they don't. I tried changing things to static and it is freaking out especially in the interface. Is this approach logical I am brand new to programming gui's? Sorry this is a novel.
interface BatchStateListener {
public void valueChanged(Cell cell, String newValue);
public void selectedCellChanged(Cell newSelectedCell)
}
class BatchState {
private String[][] values;
private Cell selectedCell;
private List<BatchStateListener> listeners;
public BatchState(int records, int fields) {
values = new String[records][fields];
selectedCell = null;
listeners = new ArrayList<BatchStateListener>();
}
public void addListener(BatchStateListener l) {
listeners.add(l);
}
public void setValue(Cell cell, String value) {
values[cell.record][cell.field] = value;
for (BatchStateListener l : listeners) {
l.valueChanged(cell, value);
}
}
public String getValue(Cell cell) {
return values[cell.record][cell.field];
}
public void setSelectedCell(Cell selCell) {
selectedCell = selCell;
for (BatchStateListener l : listeners) {
l.selectedCellChanged(selCell);
}
}
public Cell getSelectedCell() {
return selectedCell;
}
}
My questions was a bit confusing, but I came to my answer. I was just wondering how to implement this BatchState class in my code. I found that if I make it in main and pass it to the constructors frames/panels that need to communicate with each other they all can share reference to it.
I have an object, Supply, that can either be an ElecSupply or GasSupply (see related question).
Regardless of which subclass is being edited, they all have a list of BillingPeriods.
I now need to instantiate N number of BillingPeriodEditors based on the contents of that list, and am pretty baffled as to how I should do it.
I am using GWTP. Here is the code of the SupplyEditor I have just got working:
public class SupplyEditor extends Composite implements ValueAwareEditor<Supply>
{
private static SupplyEditorUiBinder uiBinder = GWT.create(SupplyEditorUiBinder.class);
interface SupplyEditorUiBinder extends UiBinder<Widget, SupplyEditor>
{
}
#Ignore
final ElecSupplyEditor elecSupplyEditor = new ElecSupplyEditor();
#Path("")
final AbstractSubTypeEditor<Supply, ElecSupply, ElecSupplyEditor> elecSupplyEditorWrapper = new AbstractSubTypeEditor<Supply, ElecSupply, ElecSupplyEditor>(
elecSupplyEditor)
{
#Override
public void setValue(final Supply value)
{
setValue(value, value instanceof ElecSupply);
if(!(value instanceof ElecSupply))
{
showGasFields();
}
else
{
showElecFields();
}
}
};
#Ignore
final GasSupplyEditor gasSupplyEditor = new GasSupplyEditor();
#Path("")
final AbstractSubTypeEditor<Supply, GasSupply, GasSupplyEditor> gasSupplyEditorWrapper = new AbstractSubTypeEditor<Supply, GasSupply, GasSupplyEditor>(
gasSupplyEditor)
{
#Override
public void setValue(final Supply value)
{
setValue(value, value instanceof GasSupply);
if(!(value instanceof GasSupply))
{
showElecFields();
}
else
{
showGasFields();
}
}
};
#UiField
Panel elecPanel, gasPanel, unitSection;
public SupplyEditor()
{
initWidget(uiBinder.createAndBindUi(this));
gasPanel.add(gasSupplyEditor);
elecPanel.add(elecSupplyEditor);
}
// functions to show and hide depending on which type...
#Override
public void setValue(Supply value)
{
if(value instanceof ElecSupply)
{
showElecFields();
}
else if(value instanceof GasSupply)
{
showGasFields();
}
else
{
showNeither();
}
}
}
Now, as the list of BillingPeriods is a part of any Supply, I presume the logic for this should be in the SupplyEditor.
I got some really good help on the thread How to access PresenterWidget fields when added dynamically, but that was before I had implemented the Editor Framework at all, so I think the logic is in the wrong places.
Any help greatly appreciated. I can post more code (Presenter and View) but I didn't want to make it too hard to read and all they do is get the Supply from the datastore and call edit() on the View.
I have had a look at some examples of ListEditor but I don't really get it!
You need a ListEditor
It depends of how you want to present them in your actual view, but the same idea apply:
public class BillingPeriodListEditor implements isEditor<ListEditor<BillingPeriod,BillingPeriodEditor>>, HasRequestContext{
private class BillingPeriodEditorSource extends EditorSource<BillingPeriodEditor>{
#Override
public EmailsItemEditor create(final int index) {
// called each time u add or retrive new object on the list
// of the #ManyToOne or #ManyToMany
}
#Override
public void dispose(EmailsItemEditor subEditor) {
// called each time you remove the object from the list
}
#Override
public void setIndex(EmailsItemEditor editor, int index) {
// i would suggest track the index of the subeditor.
}
}
private ListEditor<BillingPeriod, BillingPeriodEditor> listEditor = ListEditor.of(new BillingPeriodEditorSource ());
// on add new one ...
// apply or request factory
// you must implement the HasRequestContext to
// call the create.(Proxy.class)
public void createNewBillingPeriod(){
// create a new one then add to the list
listEditor.getList().add(...)
}
}
public class BillingPeriodEditor implements Editor<BillingPeriod>{
// edit you BillingPeriod object
}
Then in you actual editor edit as is in the path Example getBillingPeriods();
BillingPeriodListEditor billingPeriods = new BillingPeriodListEditor ();
// latter on the clickhandler
billingPeriods.createNewBillingPeriod()
You are done now.
I have this in several areas of an app I'm working on and I can see no way to replicate it outside of this app. I can't create a sscce since I can't manage to replicate this at all - This leads me to believe that it must be something caused by the parent frame / app, but I have no idea where to look.
What I see is that part of the left hand side of popup menus are not painted. I see this behaviour with JCombobox popups as well as JPopupMenu's. I've attached a couple of images to show what I mean. most of these did work properly previously and without any changes to the code where the popupmenu's are created or displayed, this problem has spread to a lot of other places now.
I'm not mixing heavyweight and lightweight components, as we only use Swing components and the two examples I show below are in completely different parts of the app. The first one is in a fairly simple panel with very little functionality, but the second example (JPoopupMenu) is in a very complex legacy panel.
On both of these and other place where I see it, I'm not altering the parent's clipping region at all and in all case, these popups are constructed and displayed on the EDT.
I know this question is rather vague, but that is because of the nature of the problem. I'll provide any requested info.
This specific case happens to be a custom combobox model, but we've seen it when using the DefaultComboBoxModel as well:
public class GroupListModel extends AbstractListModel
implements ComboBoxModel{
private List<groupObject> groups;
private groupObject selectedItem = null;
public GroupListModel() {
this(new ArrayList<groupObject>());
}
public GroupListModel(List<groupObject> groups) {
this.groups = groups;
}
#Override
public int getSize() {
return groups.size();
}
#Override
public Object getElementAt(int index) {
if(index>=groups.size()){
throw new IndexOutOfBoundsException();
}
return groups.get(index);
}
public void setGroups(List<groupObject> groups){
this.groups = groups;
fireContentsChanged(this, 0, groups.size());
}
public void addElement(groupObject group){
groups.add(group);
fireIntervalAdded(this, groups.size()-1, groups.size()-1);
}
public void addElement(groupObject group, int index){
groups.add(index, group);
fireIntervalAdded(this, index, index+1);
}
#Override
public void setSelectedItem(Object anItem) {
if(anItem instanceof groupObject){
selectedItem = (groupObject) anItem;
}else{
throw new IllegalArgumentException();
}
fireContentsChanged(this, 0, groups.size());
}
#Override
public Object getSelectedItem() {
return selectedItem;
}
This is a JPopupMenu that gets displayed when you right click using the following code:
public void mouseClicked(MouseEvent e) {
if( e.getButton()==e.BUTTON3 ){
lastClickedID = tmp.getUniqueID();
lastClickedGui = (bigEventGui) gui;
itmComplete.setText(
completed ?
ctOne.getLang("uncomplete") :
ctOne.getLang("complete") );
itmComplete.setIcon( (completed ?
iconFramework.getIcon(
iconFramework.UNCOMPLETE_ITEM,
24, false) :
iconFramework.getIcon(
iconFramework.COMPLETE_ITEM,
24, false) ));
popRCEvent.show(gui, e.getX(), e.getY() );
}
Taking out JPopupMenu.setDefaultLightWeightPopupEnabled(false); fixed it... Can somebody please try and explain why?
I have an unusual situation where I need to have a JTree with each node containing 2 checkboxes and a label (with the ability to add a listener to tell when any of the potential checkboxes are checked). I also need the root node to have the same layout (which I'm assuming means creating a JPanel with 2 JCheckBoxes and a JLabel), with the ability to select all the checkboxes down the tree if one in the root is checked.
Any guidance or examples? I've checked out previous questions on here and associated examples...some of which allowed me to get to the point of having the tree "look" but without giving me a direction for implementing the action behind it.
Thanks!
This might be a good time to look at the old JTreeTable code, which will give you a tree rendered in the first column, and the freedom to render the cells for each column to the right of the tree node as you wish, in your case putting in checkboxes and a label, and allowing you to have TableCellEditors working with your JTable as you are used to. A warning is that, while the code in that link works, it is a little convoluted.
There is an alternative. I have demoed below a Tree Table implementation that is supposed to be better, called Outline, provided by NetBeans (though you don't need to develop with the NetBeans IDE, you just need the jar). This article indicates how easy it is to be to get started.
I was able to mock up a quick example of the Outline tree table in Eclipse (with the org-netbeans-swing-outline.jar imported to my project) in about 30 minutes (I am slow at typing):
private void buildFrame() {
frame = new JFrame("Demo");
frame.setSize(300, 300);
addStuffToFrame();
frame.setVisible(true);
}
private void addStuffToFrame() {
MyTreeNode top = new MyTreeNode("top");
createNodes(top);
DefaultTreeModel model = new DefaultTreeModel(top);
//here are the netBeans tree table classes
OutlineModel outlineModel =
DefaultOutlineModel.createOutlineModel(model, new MyRowModel());
Outline outline = new Outline();
outline.setRootVisible(true);
outline.setModel(outlineModel);
frame.getContentPane().add(new JScrollPane(outline));
}
private void createNodes(MyTreeNode top) {
MyTreeNode child = new MyTreeNode("child 2");
top.add(new MyTreeNode("child 1"));
child.add(new MyTreeNode("g-child1"));
child.add(new MyTreeNode("g-child2"));
child.add(new MyTreeNode("g-child3"));
top.add(child);
top.add(new MyTreeNode("child3"));
top.add(new MyTreeNode("child4"));
}
I create a TreeNode to hold the Booleans that will interoperate well with the JTable's built-in checkbox rendering mechnanism.
public class MyTreeNode extends DefaultMutableTreeNode {
Boolean data1 = null;
Boolean data2 = null;
String name = null;
MyTreeNode (String name) {
this.name=name;
}
void setData1(Boolean val) {data1=val;}
void setData2(Boolean val) {data2=val;}
Boolean getData1() {return data1;}
Boolean getData2() {return data2;}
String getName() {return name;}
}
The netBeans RowModel is the key to making this a table instead of a simple JTree:
public class MyRowModel implements RowModel {
public Class getColumnClass(int col) {
switch (col) {
case 0: return String.class;
case 1: return Boolean.class; //these return class definitions will
case 2: return Boolean.class; //trigger the checkbox rendering
default:return null;
}
}
public int getColumnCount() {
return 3;
}
public String getColumnName(int col) {
return "";
}
public Object getValueFor(Object node, int col) {
MyTreeNode n = (MyTreeNode)node;
switch (col) {
case 0: return n.getName();
case 1: return n.getData1();
case 2: return n.getData2();
default:return null;
}
}
public boolean isCellEditable(Object node, int col) {
return col > 0;
}
public void setValueFor(Object node, int col, Object val) {
MyTreeNode n = (MyTreeNode)node;
if (col == 1) {n.setData1((Boolean)val);}
else if (col == 2) {n.setData2((Boolean)val);}
//EDIT: here is a recursive method to set all children
// selected for one of the two checkboxes as it is
// checked by the parent
for (Enumeration children = n.children();
children.hasMoreElements(); ) {
MyTreeNode child = (MyTreeNode) children.nextElement();
setValueFor(child, col, val);
}
}
}
here is the finished, albeit simplistic, product:
alt text http://img17.imageshack.us/img17/6643/picture1hz.png
I have updated the setValueFor method to iterate over a node's children and set the checkboxes as selected or deselected when a parent has been modified.
Take a look at http://www.java2s.com/Code/Java/Swing-JFC/CheckBoxNodeTreeSample.htm
It wasn't clear where the buildFrame(), addStuffToFrame() and createNodes() methods go. I put them all into an OutlineJFrame class I created that extends JFrame, and deleted the 'frame.' preface where-ever it appeared. Then in my project's main() method, it just created one of those OutlineJFrame objects and set its visible to true. When it ran, I got a resizable but empty window. Where were the rows? Where were the nodes?
Then I asked Geertjan, the NetBeans guru, what I was doing wrong, and he sent me a re-write. But it had the same behaviour.
But I know that my java is fine, because another demo project I did (FileTreeJFrame) displays outline.java objects just fine.