2008-08-05 83 views
85

¿Hay alguna forma de crear un JButton con su propio gráfico de botones y no solo con una imagen dentro del botón?Crear un JButton personalizado en Java

Si no, ¿hay alguna otra manera de crear un JButton personalizado en java?

Respuesta

85

Cuando estaba primero aprendiendo Java que tuvimos que hacer Yahtzee y yo pensamos que estaría bien para cree componentes y contenedores Swing personalizados en lugar de simplemente dibujar todo en uno JPanel. El beneficio de extender los componentes Swing, por supuesto, es tener la capacidad de agregar soporte para atajos de teclado y otras funciones de accesibilidad que no se pueden hacer simplemente teniendo un método paint() imprimiendo una imagen bonita. Sin embargo, puede que no se haga de la mejor manera, pero puede ser un buen punto de partida para usted.

Editar 8/6 - Si no era aparente en las imágenes, cada Dado es un botón en el que puede hacer clic. Esto lo moverá al DiceContainer a continuación. Al observar el código fuente, puede ver que cada botón Die se dibuja dinámicamente, en función de su valor.

alt text
alt text
alt text

Éstos son los pasos básicos:

  1. crear una clase que se extiende JComponent
  2. constructor de matriz llamada super() en sus constructores
  3. Asegúrese de que la clase implementa MouseListener
  4. poner esto en el constructor:

    enableInputMethods(true); 
    addMouseListener(this); 
    
  5. anular estos métodos:

    public Dimension getPreferredSize() 
    public Dimension getMinimumSize() 
    public Dimension getMaximumSize() 
    
  6. reemplazar este método:

    public void paintComponent(Graphics g) 
    

La cantidad de s El ritmo con el que debe trabajar cuando dibuja su botón está definido por getPreferredSize(), asumiendo que getMinimumSize() y getMaximumSize() devuelven el mismo valor. No he experimentado demasiado con esto pero, dependiendo del diseño que use para su GUI, su botón podría verse completamente diferente.

Y finalmente, el source code. En caso de que me haya perdido algo.

+1

Hola, primero gracias por el código! Sugeriría agregar un 'setActionComme (String Command)' a su código. es una de las formas de filtrar eventos en Swing. (Pero luego puede argumentar que hay 1001 cosas que podrían agregarse para mejorar un poco las cosas: P) –

+1

¿Puede poner todo el código aquí? –

+0

Para crear un dado que pueda presionar, puede usar un JButton simple antiguo (en lugar de crear una subclase o crear un JComponent personalizado) aprovechando setIcon/setPressedIcon y otras funciones de icono en JButton – ControlAltDel

6

No he hecho el desarrollo de SWING desde mis primeras clases de CS, pero si no estuviera incorporado, podrías heredar javax.swing.AbstractButton y crear el tuyo propio. Debería ser bastante simple conectar algo junto con su marco existente.

12

Siempre puedes probar la apariencia de Synth & feel. Proporciona un archivo xml que actúa como una especie de hoja de estilo, junto con las imágenes que desea usar. El código podría verse así:

try { 
    SynthLookAndFeel synth = new SynthLookAndFeel(); 
    Class aClass = MainFrame.class; 
    InputStream stream = aClass.getResourceAsStream("\\default.xml"); 

    if (stream == null) { 
     System.err.println("Missing configuration file"); 
     System.exit(-1);     
    } 

    synth.load(stream, aClass); 

    UIManager.setLookAndFeel(synth); 
} catch (ParseException pe) { 
    System.err.println("Bad configuration file"); 
    pe.printStackTrace(); 
    System.exit(-2); 
} catch (UnsupportedLookAndFeelException ulfe) { 
    System.err.println("Old JRE in use. Get a new one"); 
    System.exit(-3); 
} 

A partir de ahí, continúe y agregue su JButton como lo haría normalmente. El único cambio es que usa el método setName (cadena) para identificar a qué se debe asignar el botón en el archivo xml.

el archivo XML podría tener este aspecto:

<synth> 
    <style id="button"> 
     <font name="DIALOG" size="12" style="BOLD"/> 
     <state value="MOUSE_OVER"> 
      <imagePainter method="buttonBackground" path="dirt.png" sourceInsets="2 2 2 2"/> 
      <insets top="2" botton="2" right="2" left="2"/> 
     </state> 
     <state value="ENABLED"> 
      <imagePainter method="buttonBackground" path="dirt.png" sourceInsets="2 2 2 2"/> 
      <insets top="2" botton="2" right="2" left="2"/> 
     </state> 
    </style> 
    <bind style="button" type="name" key="dirt"/> 
</synth> 

El elemento se unen no especifica qué mapa (en este ejemplo, se va a aplicar ese estilo a los botones cuya propiedad nombre ha sido ajustado a "la suciedad ").

Y un par de enlaces útiles:

http://javadesktop.org/articles/synth/

http://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/synth.html

32

Sí, esto es posible. Una de las principales ventajas de usar Swing es la facilidad con la que se pueden crear y manipular los controles abstractos.

Aquí hay una manera rápida y sucia de extender la clase JButton existente para dibujar un círculo a la derecha del texto.

package test; 

import java.awt.Color; 
import java.awt.Container; 
import java.awt.Dimension; 
import java.awt.FlowLayout; 
import java.awt.Graphics; 

import javax.swing.JButton; 
import javax.swing.JFrame; 

public class MyButton extends JButton { 

    private static final long serialVersionUID = 1L; 

    private Color circleColor = Color.BLACK; 

    public MyButton(String label) { 
     super(label); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 

     Dimension originalSize = super.getPreferredSize(); 
     int gap = (int) (originalSize.height * 0.2); 
     int x = originalSize.width + gap; 
     int y = gap; 
     int diameter = originalSize.height - (gap * 2); 

     g.setColor(circleColor); 
     g.fillOval(x, y, diameter, diameter); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     Dimension size = super.getPreferredSize(); 
     size.width += size.height; 
     return size; 
    } 

    /*Test the button*/ 
    public static void main(String[] args) { 
     MyButton button = new MyButton("Hello, World!"); 

     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setSize(400, 400); 

     Container contentPane = frame.getContentPane(); 
     contentPane.setLayout(new FlowLayout()); 
     contentPane.add(button); 

     frame.setVisible(true); 
    } 

} 

Tenga en cuenta que por razones imperiosas paintComponent que el contenido de la tecla se pueden cambiar, pero que la frontera está pintado por el método depaintBorder. El método getPreferredSize también necesita ser administrado para admitir dinámicamente cambios en el contenido. Se debe tener cuidado al medir las métricas de fuentes y las dimensiones de la imagen.

Para crear un control en el que pueda confiar, el código anterior no es el enfoque correcto. Las dimensiones y los colores son dinámicos en Swing y dependen de la apariencia que se use. Incluso el aspecto predeterminado Metal ha cambiado en las versiones de JRE. Sería mejor implementar AbstractButton y cumplir con las directrices establecidas por la API de Swing. Un buen punto de partida es mirar las clases javax.swing.LookAndFeel y javax.swing.UIManager.

http://docs.oracle.com/javase/8/docs/api/javax/swing/LookAndFeel.html

http://docs.oracle.com/javase/8/docs/api/javax/swing/UIManager.html

La comprensión de la anatomía de LookAndFeel es útil para escribir controles: Creating a Custom Look and Feel

8

Probablemente estoy yendo un millón de kilómetros en el camino equivocado (pero solo soy joven: P). pero no podría agregar el gráfico a un panel y luego un monitor de pantalla táctil al objeto gráfico para que cuando el usuario en el gráfico se realice su acción.

+1

Esto funcionaría, pero Preferiría usar el JButton estándar que crear un tipo de botón si es posible. – Anton

Cuestiones relacionadas