Arquivos de Categoria: Java Components

Criando um JDialog a partir de um simples JOptionPane

public class CreateDialogFromOptionPane {
   public static void main(final String[] args) {
      JFrame parent = new JFrame();
      JOptionPane optionPane = new JOptionPane(“Deseja continuar?”,
              JOptionPane.QUESTION_MESSAGE,  JOptionPane.YES_NO_OPTION);

      JDialog dialog = optionPane.createDialog(parent, “Título do JDialog”);
      dialog.setVisible(true);
   }
}

Retirado de: http://www.java2s.com/Tutorial/Java/CatalogJava.htm

JButton sem bordas

Utilize o método:
setContentAreaFilled(false);

Javadoc:

public void setContentAreaFilled(boolean b)

Define a propriedade contentAreaFilled. Se true o botão pintará a área de conteúdo. Se você deseja ter um botão transparente, com somente o ícone visível, por exemplo, então você deve definir esta propriedade como false. Não chame setOpaque(false). O valor padrão para a propriedade contentAreaFilled é true. Esta função pode mudar a propriedade opaque do componente. O comportamento exato de chamar esta função varia de componente para componente e de L&F para L&F.
Parameters:
b - Se true, o conteúdo deve ser preenchido; se false a área de conteúdo não deve ser preenchida.

JTabbedPane.getTabComponentAt(int) não está funcionando

Pergunta:
Estou tentando obter todas as guias de um JTabbedPane mas de alguma forma o método getTabComponentAt sempre retorna null. Esperava após a adição das guias via addTab que pudesse recuperar uma determinada guia através getTabComponentAt. O que estou fazendo errado?

Resposta:
getTabComponentAt retorna o componente que é usado para renderização da guia em si. Para o conteúdo da guia utilize o método getComponentAt.

Não exibir bordas e barra de título de um JDialog

Utilizar o método:
setUndecorated da classe java.awt.Dialog

Segundo JavaDoc:

public void setUndecorated(boolean undecorated)

    Permite ou desativa decorações para este diálogo. Este método só pode
    ser chamado enquanto o diálogo não for exibível.

    Parâmetros:
        undecorated - true para que nenhuma decoração seja habilitada no 
             diálogo; false para que decorações seja habilitadas no diálogo.
    Throws:
        IllegalComponentStateException - se o diálogo está visível.
    Desde:
        1.4

JTree dentro de um JComboBox

Esta é uma tradução de uma postagem no Santosh Kumar’s Weblog. Estava precisando de algo assim e após uma pesquisa encontrei esta solução. Resolvi então postar aqui os passos. O original está aqui.

JComboBox requer ComboBoxModel, mas temos TreeModel, porque não tentar criar um adaptador chamado TreeListModel que nós permita ver TreeModel como se fosse um ListModel?

class TreeListModel extends AbstractListModel implements ComboBoxModel{
    private TreeModel treeModel;
    private Object selectedObject; 

    public TreeListModel(TreeModel treeModel){
        this.treeModel = treeModel;
    } 

    public int getSize(){
        ????
    } 

    public Object getElementAt(int index){
        ????
    } 

    public void setSelectedItem(Object anObject){
        if((selectedObject!=null && !selectedObject.equals(anObject)) ||
                selectedObject==null && anObject!=null){
            selectedObject = anObject;
            fireContentsChanged(this, -1, -1);
        }
    } 

    public Object getSelectedItem() {
        return selectedObject;
    }
} 

Precisamos implementar getSize() e getElementAt(index),mas como?

– tamanho da lista (size) = total de nós da árvore

– elemento i na lista = linha i na árvore quanto completamento expandida

A resposta está em DefaultMutableTreeNode.PreorderEnumeration que na sua implementação assume que os nós são objetos TreeNode. Como queremos que a solução seja para qualquer TreeModel substituiremos o método enumeration() da interface TreeModel desta forma:

class ChildrenEnumeration implements Enumeration{
    TreeModel treeModel;
    Object node;
    int index = -1; 

    public ChildrenEnumeration(TreeModel treeModel, Object node){
        this.treeModel = treeModel;
        this.node = node;
    } 

    public boolean hasMoreElements(){
        return index<treeModel.getChildCount(node)-1;
    } 

    public Object nextElement(){
        return treeModel.getChild(node, ++index);
    }
} 

Agora copiamos DefaultMutableTreeNode.PreorderEnumeration e removemos os vestígios da interface TreeNode:

class PreorderEnumeration implements Enumeration{
    private TreeModel treeModel;
    protected Stack stack; 

    public PreorderEnumeration(TreeModel treeModel){
        this.treeModel = treeModel;
        Vector v = new Vector(1);
        v.addElement(treeModel.getRoot());
        stack = new Stack();
        stack.push(v.elements());
    } 

    public boolean hasMoreElements(){
        return (!stack.empty() &&
                ((Enumeration)stack.peek()).hasMoreElements());
    } 

    public Object nextElement(){
        Enumeration enumer = (Enumeration)stack.peek();
        Object node = enumer.nextElement();
        if(!enumer.hasMoreElements())
            stack.pop();
        Enumeration children = new ChildrenEnumeration(treeModel, node);
        if(children.hasMoreElements())
            stack.push(children);
        return node;
    }
} 

Agora completaremos os métodos deixados para trás em TreeListModel:

public int getSize(){
        int count = 0;
        Enumeration enumer = new PreorderEnumeration(treeModel);
        while(enumer.hasMoreElements()){
            enumer.nextElement();
            count++;
        }
        return count;
    } 

    public Object getElementAt(int index){
        Enumeration enumer = new PreorderEnumeration(treeModel);
        for(int i=0; i<index; i++)
            enumer.nextElement();
        return enumer.nextElement();
    } 

Nosso TreeListModel está completo. Vamos agora para parte do Renderer.

JComboBox requer ListCellRenderer mas temos TreeCellRenderer. Escreveremos então um adaptador para isso também.

public class TreeListCellRenderer extends JPanel implements ListCellRenderer{
    private static final JTree tree = new JTree();
    TreeModel treeModel;
    TreeCellRenderer treeRenderer; 

    public TreeListCellRenderer(TreeModel treeModel, TreeCellRenderer treeRenderer){
        this.treeModel = treeModel;
        this.treeRenderer = treeRenderer;
        setOpaque(false);
    } 

    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus){
        if(value==null){ //if selected value is null
            return this;
        } 

        boolean leaf = treeModel.isLeaf(value);
        Component comp = treeRenderer.getTreeCellRendererComponent(tree, value, isSelected, true, leaf, index, cellHasFocus); 

        return comp;
    }
}

No entanto, há um problema com a implementação acima: o renderer não esta sendo recuado de acordo com a profundidade do nó da árvore.

Como é que vamos recuar um renderer? A resposta é EmptyBorder cuja inserção esquerda é igual ao número de pixels reqd para recuo.

class IndentBorder extends EmptyBorder{
    int indent = UIManager.getInt("Tree.leftChildIndent"); 

    public IndentBorder(){
        super(0, 0, 0, 0);
    } 

    public void setDepth(int depth){
        left = indent*depth;
    }
} 

E TreeListCellRenderer é modificado para usar IndentBorder:

class TreeListCellRenderer extends JPanel implements ListCellRenderer{
    private static final JTree tree = new JTree();
    TreeModel treeModel;
    TreeCellRenderer treeRenderer;
    IndentBorder indentBorder = new IndentBorder(); 

    public TreeListCellRenderer(TreeModel treeModel, TreeCellRenderer treeRenderer){
        this.treeModel = treeModel;
        this.treeRenderer = treeRenderer;
        setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
        setBorder(indentBorder);
        setOpaque(false);
    } 

    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus){
        if(value==null){ //if selected value is null
            removeAll();
            return this;
        } 

        boolean leaf = treeModel.isLeaf(value);
        Component comp = treeRenderer.getTreeCellRendererComponent(tree, value, isSelected, true, leaf, index, cellHasFocus);
        removeAll();
        add(comp); 

        int depth = //somehow calculate depath
        indentBorder.setDepth(depth); 

        return this;
    }
}

Quase tudo está concluído, exceto o cálculo da profundidade de um nó.

Adicionamos uma variável membro chamada de ‘depth’ para a classe ChildrenEnumeration. Esta classe não faz qualquer outra coisa além de assegurar o valor da profundidade:

class ChildrenEnumeration implements Enumeration{
    .....
    int depth;
    .....
} 

A classe PreorderEnumeration é, então, modificada para calcular a profundidade e devolver a profundidade do elemento:

class PreorderEnumeration implements Enumeration{
    .....
    private int depth = 0; 

    ......

    public Object nextElement(){
        Enumeration enumer = (Enumeration)stack.peek();
        Object node = enumer.nextElement();
        depth = enumer instanceof ChildrenEnumeration
                ? ((ChildrenEnumeration)enumer).depth
                : 0;
        if(!enumer.hasMoreElements())
            stack.pop();
        ChildrenEnumeration children = new ChildrenEnumeration(treeModel, node);
        children.depth = depth+1;
        if(children.hasMoreElements()){
            stack.push(children);
        }
        return node;
    } 

    public int getDepth(){
        return depth;
    }
} 

Agora TreeListRenderer usa PreorderEnumeration para encontrar a profundidade do renderer:

        // compute the depth of value
        PreorderEnumeration enumer = new PreorderEnumeration(treeModel);
        for(int i = 0; i<=index; i++)
            enumer.nextElement();
        indentBorder.setDepth(enumer.getDepth()); 

Para utilizar nossa implementação:

 JComboBox comboBox = new JComboBox(new TreeListModel(treeModel));
 comboBox.setRenderer(new TreeListCellRenderer(treeModel, treeCellRenderer));