2013-03-14 12 views
6

Sto cercando di creare un'interfaccia utente della griglia (5 * 5) utilizzando le classi Swing. Ho provato un ciclo annidato e aggiungendo un jPanel dinamicamente a jFrame. E ho anche provato a cambiare il colore di sfondo di ogni jPanel quando l'utente fa clic e lo lascia cadere. Ma con il mio codice ci sono enormi intervalli tra ogni cella e non riesco a far funzionare l'evento di trascinamento.Come disegnare la griglia utilizzando la classe swing Java e rilevare la posizione del mouse quando si fa clic e si trascina

public class clsCanvasPanel extends JPanel { 
    private static final int intRows = 5; 
    private static final int intCols = 5; 
    private List<JPanel> jpllist = new ArrayList<JPanel>(); 

    public clsCanvasPanel() {       
     /* 
     * 
     * Add eventListener to individual JPanel within CanvasPanel 
     * 
     * 
     * TODO : 
     * 1) mousePressed --> update Temperature and HeatConstant of clsElement Class 
     * 2) start a new thread and 
     * 3) call clsElement.run() method 
     * 
     * 
     * Right Now : it updates the colours of the JPanel 
     * */ 
      MouseListener mouseListener = new MouseAdapter() { 
      @Override 
      public void mousePressed(MouseEvent e) { 
       JPanel panel = (JPanel) e.getSource(); 

       Component[] components = panel.getComponents(); 
       for (Component component : components) { 
        component.setVisible(!component.isVisible()); 
        component.setBackground(new Color(255,255,0)); 
       } 
       panel.revalidate(); 
       panel.repaint(); 
      } 
      }; 

      //TODO : refactoring 
      GridLayout gdlyPlates = new GridLayout(); 
      gdlyPlates.setColumns(intCols); 
      gdlyPlates.setRows(intRows); 
      gdlyPlates.setHgap(0); 
      gdlyPlates.setVgap(0); 
      setLayout(gdlyPlates); 

      //TODO : refactoring 
      for (int row = 0; row < intRows; row++) { 
       for (int col = 0; col < intCols; col++) { 
       JPanel panel = new JPanel(new GridBagLayout()); 
       panel.setOpaque(false); 
       JPanel jl = new JPanel(); 
       jl.setVisible(true); 
       panel.add(jl); 
       panel.addMouseListener(mouseListener); 
       jpllist.add(panel); 
       add(panel); 
       } 
      } 
    } 
} 

Così ora sto cercando di creare un pannello e disegnare le griglie su di esso, quindi rileva la posizione del mouse sulla griglia, cambiare ulteriormente il colore di ogni cellula.

Qualcuno potrebbe darmi alcuni consigli su come implementare questa griglia su JPanel e cambiare il colore di una cella selezionata.

risposta

31

Ci sono diversi modi per farlo funzionare, a seconda di cosa si vuole raggiungere.

Questo primo esempio utilizza semplicemente l'API grafica 2D per eseguire il rendering delle celle e un MouseMotionListener per monitorare quale cella è evidenziata.

enter image description here

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Point; 
import java.awt.Rectangle; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.util.ArrayList; 
import java.util.List; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class TestGrid01 { 

    public static void main(String[] args) { 
     new TestGrid01(); 
    } 

    public TestGrid01() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(new TestPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     private int columnCount = 5; 
     private int rowCount = 5; 
     private List<Rectangle> cells; 
     private Point selectedCell; 

     public TestPane() { 
      cells = new ArrayList<>(columnCount * rowCount); 
      MouseAdapter mouseHandler; 
      mouseHandler = new MouseAdapter() { 
       @Override 
       public void mouseMoved(MouseEvent e) { 
        Point point = e.getPoint(); 

        int width = getWidth(); 
        int height = getHeight(); 

        int cellWidth = width/columnCount; 
        int cellHeight = height/rowCount; 

        selectedCell = null; 
        if (e.getX() >= xOffset && e.getY() >= yOffset) { 

         int column = (e.getX() - xOffset)/cellWidth; 
         int row = (e.getY() - yOffset)/cellHeight; 

         if (column >= 0 && row >= 0 && column < columnCount && row < rowCount) { 

          selectedCell = new Point(column, row); 

         } 

        } 
        repaint(); 

       } 
      }; 
      addMouseMotionListener(mouseHandler); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(200, 200); 
     } 

     @Override 
     public void invalidate() { 
      cells.clear(); 
      selectedCell = null; 
      super.invalidate(); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 

      int width = getWidth(); 
      int height = getHeight(); 

      int cellWidth = width/columnCount; 
      int cellHeight = height/rowCount; 

      int xOffset = (width - (columnCount * cellWidth))/2; 
      int yOffset = (height - (rowCount * cellHeight))/2; 

      if (cells.isEmpty()) { 
       for (int row = 0; row < rowCount; row++) { 
        for (int col = 0; col < columnCount; col++) { 
         Rectangle cell = new Rectangle(
           xOffset + (col * cellWidth), 
           yOffset + (row * cellHeight), 
           cellWidth, 
           cellHeight); 
         cells.add(cell); 
        } 
       } 
      } 

      if (selectedCell != null) { 

       int index = selectedCell.x + (selectedCell.y * columnCount); 
       Rectangle cell = cells.get(index); 
       g2d.setColor(Color.BLUE); 
       g2d.fill(cell); 

      } 

      g2d.setColor(Color.GRAY); 
      for (Rectangle cell : cells) { 
       g2d.draw(cell); 
      } 

      g2d.dispose(); 
     } 
    } 
} 

Questo esempio fa ridimensionare la griglia con la finestra, ma sarebbe un cambiamento banale per rendere le celle di dimensioni fisse.

Partenza 2D Graphics per maggiori dettagli

aggiornamento con l'esempio componente

Questo esempio utilizza una serie di JPanel s per rappresentare ogni cella.

Ogni cella è definita con larghezza e altezza fisse e non viene ridimensionata con la finestra principale.

enter image description here

In questo esempio, ogni pannello cella ha il proprio listener del mouse. Non sarebbe eccessivamente difficile ricodificarlo in modo che il pannello principale avesse un singolo listener del mouse e gestisse invece il carico di lavoro stesso.

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.border.Border; 
import javax.swing.border.MatteBorder; 

public class TestGrid02 { 

    public static void main(String[] args) { 
     new TestGrid02(); 
    } 

    public TestGrid02() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(new TestPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     public TestPane() { 
      setLayout(new GridBagLayout()); 

      GridBagConstraints gbc = new GridBagConstraints(); 
      for (int row = 0; row < 5; row++) { 
       for (int col = 0; col < 5; col++) { 
        gbc.gridx = col; 
        gbc.gridy = row; 

        CellPane cellPane = new CellPane(); 
        Border border = null; 
        if (row < 4) { 
         if (col < 4) { 
          border = new MatteBorder(1, 1, 0, 0, Color.GRAY); 
         } else { 
          border = new MatteBorder(1, 1, 0, 1, Color.GRAY); 
         } 
        } else { 
         if (col < 4) { 
          border = new MatteBorder(1, 1, 1, 0, Color.GRAY); 
         } else { 
          border = new MatteBorder(1, 1, 1, 1, Color.GRAY); 
         } 
        } 
        cellPane.setBorder(border); 
        add(cellPane, gbc); 
       } 
      } 
     } 
    } 

    public class CellPane extends JPanel { 

     private Color defaultBackground; 

     public CellPane() { 
      addMouseListener(new MouseAdapter() { 
       @Override 
       public void mouseEntered(MouseEvent e) { 
        defaultBackground = getBackground(); 
        setBackground(Color.BLUE); 
       } 

       @Override 
       public void mouseExited(MouseEvent e) { 
        setBackground(defaultBackground); 
       } 
      }); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(50, 50); 
     } 
    } 
} 
+0

ciao, mi rendo conto che questo è un post davvero vecchio. Ehi @MadProgrammer, il tuo codice è fantastico!, L'ho afferrato per armeggiare con esso per un compito che ho, ma sono un po 'sottaceto, questo è esattamente ciò di cui ho bisogno, ma ho bisogno di fare la finestra 1080x760, avere 1700 celle e rendere ogni cella 20x20. Ora ho riorganizzato la finestra e ho creato le 1700 celle, il problema che sto avendo è che quando provo a ridimensionare le celle a 20x20 l'ascoltatore del mouse impazzisce e non funziona correttamente ... Ho provato cambiando la cellWidth e cellHeight variabili ... ma non funziona così bene ... qualche pensiero? – Twhite1195

+0

@ Twhite1195 Quale versione, la prima o la seconda? – MadProgrammer

+0

@MadProgrammer In primo luogo, il secondo ha funzionato alla grande ... finché non ho ridimensionato le celle – Twhite1195

0

Nell'esempio MouseListener nel metodo mouseMoved, si potrebbe prendere in considerazione l'xOffset/YOffset anche se per il riconoscimento delle cellule più liscia.

1

Non mi piace il rendering dei bordi poiché all'interno della griglia alcuni sono stati duplicati se ci fosse più dell'esempio. Credo che questa soluzione è meglio:

private int width; 
private int height; 

// ... 

for (int row = 0; row <= this.height; row++) { 
    for (int col = 0; col <= this.width; col++) { 
     gbc.gridx = col; 
     gbc.gridy = row; 

     CellPane cellPane = new CellPane(); 
     Border border = new MatteBorder(1, 1, (row == this.height ? 1 : 0), (col == this.width ? 1 : 0), Color.GRAY); 

     cellPane.setBorder(border); 
     this.add(cellPane, gbc); 
    } 
} 

Edit:

La mia soluzione è migliore, perché se il codice originale sarà celle 5x5, ma di più, come ad esempio 10x10 ... bordi interni di alcune cellule del sarà in contatto e per creare alcuni posti griglia spessa. È bello vedere sullo screenshot thick grid

+0

Potresti [modificare] la tua risposta per spiegare perché la tua soluzione risolve il problema? –