Events GWT CellTree,具有一个可选的弹出菜单,可在单击树节点时触发
我想制作一个GWT CellTree,它有一个可选的弹出菜单,点击TreeNode就会触发 所以我制作了一个CustomTreeModel。这是:Events GWT CellTree,具有一个可选的弹出菜单,可在单击树节点时触发,events,gwt,tree,selection,Events,Gwt,Tree,Selection,我想制作一个GWT CellTree,它有一个可选的弹出菜单,点击TreeNode就会触发 所以我制作了一个CustomTreeModel。这是: public class CustomTreeModel implements TreeViewModel { /** * Save visited URL. We'll use it later to determine if tree node needs to be opened. * We decode the query strin
public class CustomTreeModel implements TreeViewModel {
/**
* Save visited URL. We'll use it later to determine if tree node needs to be opened.
* We decode the query string in URL so that token has a chance of matching (e.g., convert %20 to space).
*/
private final String url = URL.decodeQueryString(Window.Location.getHref());
private final NavNode navNode;
private final TokenService<MainEventBus> tokenService;
/**
* A selection model shared across all nodes in the tree.
*/
private final SingleSelectionModel<NavNode> selectionModel = new SingleSelectionModel<NavNode>();
public CustomTreeModel(NavNode navNode, TokenService tokenService) {
this.navNode = navNode;
this.tokenService = tokenService;
}
@Override
public <T> NodeInfo<?> getNodeInfo(T value) {
DefaultNodeInfo<NavNode> result = null;
if (value == null) {
// LEVEL 0.
// We passed null as the root value. Return the immediate descendants.
result = new DefaultNodeInfo<NavNode>(getDataProvider(navNode), getCell(), selectionModel, null);
} else if (value instanceof NavNode) {
// all other levels
// We pass a node, return its immediate descendants.
// select node if URL contains params in node's target or one of node's option's target
NavNode currNode = (NavNode) value;
if (isSelected(currNode)) {
selectionModel.setSelected(currNode, true);
}
if (currNode.hasOptions()) { // add pop-up menu to this node if it has options
result = new DefaultNodeInfo<NavNode>(getDataProvider(currNode), getCell(), selectionModel, new NodeSelectionEventManager(currNode), null);
} else {
result = new DefaultNodeInfo<NavNode>(getDataProvider(currNode), getCell(), selectionModel, null);
}
}
return result;
}
@Override
public boolean isLeaf(Object value) {
boolean result = true;
if (value == null) {
if (navNode.hasChildren()) {
result = false;
}
} else if (value instanceof NavNode) {
NavNode currentNode = (NavNode) value;
if (currentNode.hasChildren()) {
result = false;
}
}
return result;
}
// Create a data provider that contains the immediate descendants.
private ListDataProvider<NavNode> getDataProvider(NavNode node) {
return new ListDataProvider<NavNode>(node.getChildren());
}
// Create a cell to display a descendant.
private Cell<NavNode> getCell() {
Cell<NavNode> cell = new AbstractCell<NavNode>() {
@Override
public void render(Context context, NavNode value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.getName());
}
}
};
return cell;
}
private boolean isSelected(NavNode node) {
boolean selected = false;
if (node != null) {
if (url.contains(tokenService.getToken(node))) {
selected = true;
} else {
for (NavOption option: node.getOptions()) {
if (url.contains(tokenService.getToken(option))) {
selected = true;
break;
}
}
}
}
return selected;
}
class NavNodeSelectionHandler implements SelectionChangeEvent.Handler {
private final VerticalPanel optionsContainer;
private final DecoratedPopupPanel optionsPopup;
public NavNodeSelectionHandler() {
optionsPopup = new DecoratedPopupPanel(true);
optionsContainer = new VerticalPanel();
optionsContainer.setWidth("125px");
// TODO provide a debug id... this will most likely necessitate generation of a unique key
optionsPopup.setWidget(optionsContainer);
}
@Override
public void onSelectionChange(SelectionChangeEvent event) {
NavNode node = selectionModel.getSelectedObject();
for (NavOption option: node.getOptions()) {
optionsContainer.add(new Hyperlink(option.getName(), tokenService.getToken(option)));
}
// Reposition the popup relative to node
UIObject source = (UIObject) event.getSource();
int left = source.getAbsoluteLeft() + 25;
int top = source.getAbsoluteTop();
optionsPopup.setPopupPosition(left, top);
// Show the popup
optionsPopup.show();
}
}
class NodeSelectionEventManager implements CellPreviewEvent.Handler<NavNode> {
private final VerticalPanel optionsContainer;
private final DecoratedPopupPanel optionsPopup;
public NodeSelectionEventManager(NavNode node) {
optionsPopup = new DecoratedPopupPanel(true);
optionsContainer = new VerticalPanel();
optionsContainer.setWidth("125px");
for (NavOption option: node.getOptions()) {
optionsContainer.add(new Hyperlink(option.getName(), tokenService.getToken(option)));
}
// TODO provide a debug id... this will most likely necessitate generation of a unique key
optionsPopup.setWidget(optionsContainer);
}
@Override
public void onCellPreview(CellPreviewEvent<NavNode> event) {
// Reposition the popup relative to node
UIObject source = (UIObject) event.getDisplay();
int left = source.getAbsoluteLeft() + 25;
int top = source.getAbsoluteTop();
optionsPopup.setPopupPosition(left, top);
// Show the popup
optionsPopup.show();
}
}
}
我正在使用一个通用bean NavNode来帮助我确定何时有一个叶,何时有一个选项NavOption或包含用于超链接构建的目标的选项
我想,当我点击CellTree中的节点树节点时,会出现一个弹出菜单DecoratedPopupPanel,但只针对那些具有选项的节点
我曾尝试在构建DefaultNodeInfo时使用任何一种内部处理程序实现,但都没有成功。希望通过上面的代码示例,您可以看到我正在尝试做什么
下面是一个将SelectionChangeEvent.Handler添加到SingleSelectionModel的变量
if (currNode.hasOptions()) { // add pop-up menu to this node if it has options
selectionModel.addSelectionChangeHandler(new NavNodeSelectionHandler());
result = new DefaultNodeInfo<NavNode>(getDataProvider(currNode), getCell(), selectionModel, null);
}
发生的情况是,尝试强制转换事件失败,并出现ClassCastException。
我想在UIObject上获得一个句柄,以便定位弹出窗口。我想我需要一个树状物的把手,但我不知道怎么做
CellTree、TreeViewModel、SelectionModel和friends是我见过的最迟钝的API之一
非常感谢GWT专家的帮助 我的一位聪明的同事找到了一个解决方案 以下是我们的结论:
public class CustomTreeModel implements TreeViewModel {
/**
* Save visited URL. We'll use it later to determine if tree node needs to be opened.
* We decode the query string in URL so that token has a chance of matching (e.g., convert %20 to space).
*/
private final String url = URL.decodeQueryString(Window.Location.getHref());
private final NavNode navNode;
private final TokenService<MainEventBus> tokenService;
/**
* A selection model shared across all nodes in the tree.
*/
private final SingleSelectionModel<NavNode> selectionModel = new SingleSelectionModel<NavNode>();
public CustomTreeModel(NavNode navNode, TokenService tokenService) {
this.navNode = navNode;
this.tokenService = tokenService;
}
@Override
public <T> NodeInfo<?> getNodeInfo(T value) {
DefaultNodeInfo<NavNode> result = null;
if (value == null) {
// LEVEL 0.
// We passed null as the root value. Return the immediate descendants.
result = new DefaultNodeInfo<NavNode>(getDataProvider(navNode), getCell(), selectionModel, null);
} else if (value instanceof NavNode) {
// all other levels
// We pass a node, return its immediate descendants.
// select node if URL contains params in node's target or one of node's option's target
NavNode currNode = (NavNode) value;
if (isSelected(currNode)) {
selectionModel.setSelected(currNode, true);
}
result = new DefaultNodeInfo<NavNode>(getDataProvider(currNode), getCell(), selectionModel, null);
}
return result;
}
@Override
public boolean isLeaf(Object value) {
boolean result = true;
if (value == null) {
if (navNode.hasChildren()) {
result = false;
}
} else if (value instanceof NavNode) {
NavNode currentNode = (NavNode) value;
if (currentNode.hasChildren()) {
result = false;
}
}
return result;
}
// Create a data provider that contains the immediate descendants.
private ListDataProvider<NavNode> getDataProvider(NavNode node) {
return new ListDataProvider<NavNode>(NavNodeUtil.getHeadedChildren(node.getChildren(), 1));
}
// Create a cell to display a descendant.
private Cell<NavNode> getCell() {
return new TreeCell();
}
private boolean isSelected(NavNode node) {
boolean selected = false;
if (node != null) {
if (url.contains(tokenService.getToken(node))) {
selected = true;
} else {
for (NavOption option: node.getOptions()) {
if (url.contains(tokenService.getToken(option))) {
selected = true;
break;
}
}
}
}
return selected;
}
class TreeCell extends AbstractCell<NavNode> {
public TreeCell() {
super("click", "keydown");
}
@Override
public void onBrowserEvent(Context context, Element parent, NavNode currNode,
NativeEvent event, ValueUpdater<NavNode> valueUpdater) {
// Check that the value is not null.
if (currNode == null) {
return;
}
if (currNode.hasOptions()) { // add pop-up menu to this node if it has options
final DecoratedPopupPanel optionsPopup = new DecoratedPopupPanel(true);
final VerticalPanel optionsContainer = new VerticalPanel();
optionsContainer.setWidth("125px");
for (NavOption option: currNode.getOptions()) {
optionsContainer.add(new Hyperlink(option.getName(), tokenService.getToken(option)));
}
// TODO provide a debug id... this will most likely necessitate generation of a unique key
optionsPopup.setWidget(optionsContainer);
// Reposition the popup relative to node
final int left = parent.getAbsoluteLeft() + 25;
final int top = parent.getAbsoluteTop();
optionsPopup.setPopupPositionAndShow(new PopupPanel.PositionCallback() {
@Override
public void setPosition(int offsetWidth, int offsetHeight) {
optionsPopup.setPopupPosition(left, top);
}
});
}
super.onBrowserEvent(context, parent, currNode, event, valueUpdater);
}
@Override
public void render(Context context, NavNode value, SafeHtmlBuilder sb) {
if (value != null) {
sb.appendEscaped(value.getName());
}
}
}
}
注意TreeCell会覆盖onBrowserEvent。从这里我们可以获得节点上的句柄并定位弹出窗口。弹出窗口通过回调进行实例化。奇怪
NavNodeUtil在计算子节点数量并为超过某个阈值的节点的子节点添加A、B、C…Z分类标题时发挥了一些神奇的作用。我有一个基于GWT树的IML,它满足上述用例,但不适用于大型树。