Vaadin,通过 setContent() 切换内容不显示

Vaadin, Switching Content via setContent() not displaying

Vaadin 7.6.2

举个例子:

import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;

public class MyClass extends Panel {

    TextField        myField  = new TextField();
    HorizontalLayout hLayout  = new HorizontalLayout( myField );
    VerticalLayout   vLayout  = new VerticalLayout( myField );    
    Button           button   = new Button( "Press Me" );

    public MyClass() {
        super();
        applySettings();
    }

    private void applySettings() {
        button.addClickListener(new ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                setContent( hLayout );
            }
        });

        vLayout.addComponent( button );


        this.setContent( vLayout );
    }
}

当我单击按钮时,vLayout 消失,但 hLayout(带有 myField)没有出现。我缺少哪一步?或者,是否有其他方法可以做到这一点?

如果我添加辅助文本字段,如下所示:

TextField        myField  = new TextField();
TextField        myField2 = new TextField();  // tf2
HorizontalLayout hLayout  = new HorizontalLayout( myField );
VerticalLayout   vLayout  = new VerticalLayout( myField2 );  // tf2

它似乎有效,但我想要实现的是能够使用切换布局中的字段(及其数据)动态切换我的布局。

嗯,看来我可能已经解决了。

import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;

public class MyClass extends Panel {

    TextField        myField  = new TextField();
    HorizontalLayout hLayout  = new HorizontalLayout();
    VerticalLayout   vLayout  = new VerticalLayout();    
    Button           button   = new Button( "Press Me" );

    public MyClass() {
        super();
        applySettings();
    }

    private void applySettings() {
        button.addClickListener(new ClickListener() {
            @Override
            public void buttonClick(Button.ClickEvent event) {
                vLayout.removeAllComponents();   // this is optional
                hLayout.addComponent( myField );
                setContent( hLayout );
            }
        });

        vLayout.addComponents( myField, button );

        this.setContent( vLayout );
    }
}

如果我不在布局构造函数中添加 myField,而是稍后在代码中添加它,似乎可以工作。

更新

经过更多测试后,似乎无论最后为给定字段调用 addComponent() 哪个布局,该布局都会获取该字段的句柄。这种行为看起来很奇怪,如果有人能解释这是为什么?那将是有启发性的。

一个组件不能同时有 2 个 parent(在你的例子中是 hLayout & vLayout),因此如果它已经有一个,Vaadin 会把它从前一个 parent 并将其作为 child 添加到当前 child。这是继承自AbstractComponentContaineraddComponent方法:

/**
 * This only implements the events and component parent calls. The extending
 * classes must implement component list maintenance and call this method
 * after component list maintenance.
 * 
 * @see com.vaadin.ui.ComponentContainer#addComponent(Component)
 */
@Override
public void addComponent(Component c) {
    // Make sure we're not adding the component inside it's own content
    if (isOrHasAncestor(c)) {
        throw new IllegalArgumentException(
                "Component cannot be added inside it's own content");
    }

    if (c.getParent() != null) {
        // If the component already has a parent, try to remove it
        AbstractSingleComponentContainer.removeFromParent(c);
    }

    c.setParent(this);
    fireComponentAttachEvent(c);
    markAsDirty();
}

如果你在 debug mode, you can somewhat see an image of the composition tree in your browser by adding ?debug to your URL, something like http://localhost:8080/?debug