我正在尝试在JavaFX中创建自己的控件。 我的问题是我的控件不是静态的(例如,标签,按钮...)而是动态的(例如,ListView),因此会不断添加和删除新记录。 我不确定如何在JavaFX中实现它,因此,为了获得一种感觉,我想重新创建一个类似于ListView的控件。 在下面,我写了一个小例子。
该示例可以正常工作,但感觉有点脏。 为了使所有内容保持简洁,我不想使用CSS和FXML。
我该如何实施此清理程序,尤其是在更复杂的情况下?
MyList.java
public class MyList extends Control
{
private ListProperty<MyListItem> mItems;
public MyList()
{
mItems = new SimpleListProperty<>(FXCollections.observableArrayList());
}
@Override
protected Skin<?> createDefaultSkin()
{
return new MyListSkin(this);
}
public ObservableList<MyListItem> getItems()
{
return mItems.get();
}
public void setItems(ObservableList<MyListItem> pItems)
{
mItems.set(pItems);
}
public ListProperty<MyListItem> itemsProperty()
{
return mItems;
}
}
MyListItem.java
public class MyListItem
{
private StringProperty mName;
public MyListItem(String pName)
{
mName = new SimpleStringProperty(pName);
}
public String getName()
{
return mName.get();
}
public void setName(String pName)
{
mName.set(pName);
}
public StringProperty nameProperty()
{
return mName;
}
}
MyListSkin.java
public class MyListSkin extends SkinBase<MyList>
{
private VBox mVBox;
private Map<MyListItem, Label> mNodes;
protected MyListSkin(MyList pControl)
{
super(pControl);
mVBox = new VBox();
mNodes = new HashMap<>();
getChildren().add(mVBox);
getSkinnable().getItems().addListener(new ListChangeListener<MyListItem>()
{
@Override
public void onChanged(Change<? extends MyListItem> pChange)
{
removeItems(pChange.getRemoved());
addItems(pChange.getAddedSubList());
}
});
getSkinnable().itemsProperty().addListener(new ChangeListener<ObservableList<MyListItem>>()
{
@Override
public void changed(ObservableValue<? extends ObservableList<MyListItem>> pObservable,
ObservableList<MyListItem> pOldValue, ObservableList<MyListItem> pNewValue)
{
clearItems();
addItems(pNewValue);
}
});
addItems(getSkinnable().getItems());
}
private void addItems(List<? extends MyListItem> list)
{
for(MyListItem lItem : list)
{
Label lLabel = new Label();
lLabel.setMinWidth(Control.USE_PREF_SIZE);
lLabel.setPrefWidth(200);
lLabel.textProperty().bind(lItem.nameProperty());
mVBox.getChildren().add(lLabel);
mNodes.put(lItem, lLabel);
}
}
private void removeItems(List<? extends MyListItem> list)
{
for(MyListItem lItem : list)
{
mVBox.getChildren().remove(mNodes.get(lItem));
mNodes.remove(lItem);
}
}
private void clearItems()
{
for(Map.Entry<MyListItem, Label> lEntry : mNodes.entrySet())
{
mVBox.getChildren().remove(lEntry.getValue());
mNodes.remove(lEntry.getKey());
}
}
}
MainApplication.java
public class MainApplication extends Application
{
@Override
public void start(Stage pPrimaryStage)
{
MyList lControl = new MyList();
lControl.getItems().add(new MyListItem("Test 1"));
lControl.getItems().add(new MyListItem("Test 2"));
lControl.getItems().add(new MyListItem("Test 3"));
lControl.getItems().add(new MyListItem("Test 4"));
Pane lRoot = new Pane();
lRoot.getChildren().add(lControl);
pPrimaryStage.setScene(new Scene(lRoot, 800, 800));
pPrimaryStage.show();
}
public static void main(String[] pArguments)
{
launch(pArguments);
}
}
答案 0 :(得分:0)
如何将数据,逻辑和图形分开?
单独的类就是这样做的,MyListItem
是您的数据,MyList
是您的逻辑,MyListSkin
是您的图形。
我应该使用BehaviorBase吗?
取决于您,如果您愿意,我建议阅读ListViewBehavior
并可能从中扩展。还要检查CellBehaviorBase
及其子类。
如何跟踪
MyListItem
对象及其对应的图形表示/节点?
不太清楚您要问的是什么,请在Control
中跟踪它们,并在Skin
中跟踪图形表示,好像您在做什么。
我应该如何处理初始化?
您的工作方式似乎不错。
如何使其保持同步?
您可以通过其他方式使其他所有内容保持同步,监听Control
中的更改并更新Skin
,就像您在做的那样,这行不通吗?
如果您要为列表中的各个Label
自定义图形,则可以通过MyListSkin
处理某些一般情况下的图形,例如。为偶数或奇数索引元素设置PseudoClass
。