2013-03-14 4 views
6

Ich versuche, ein Raster UI (5 * 5) mit Swing-Klassen zu erstellen. Ich habe eine verschachtelte Schleife ausprobiert und ein jPanel dynamisch zum jFrame hinzugefügt. Und ich habe auch versucht, die Hintergrundfarbe jedes jPanels zu ändern, wenn der Benutzer darauf klickt und darüber fällt. Aber mit meinem Code gibt es riesige Lücken zwischen jeder Zelle und ich kann das Ziehereignis nicht zum Funktionieren bringen.Wie zeichne Raster mit Swing-Klasse Java und erkennen Mausposition, wenn klicken und ziehen

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); 
       } 
      } 
    } 
} 

So, jetzt versuche ich, eine Platte und ziehen Gitter auf, es zu schaffen, erkennt dann die Mausposition auf dem Gitter, das weiterhin die Farbe jeder Zelle ändern.

Könnte mir jemand Ratschläge geben, wie man dieses Raster auf JPanel implementiert und die Farbe einer ausgewählten Zelle ändert.

Antwort

31

Es gibt eine Reihe von Möglichkeiten, dies zu erreichen, je nachdem, was Sie erreichen möchten.

Dieses erste Beispiel verwendet einfach die 2D-Grafik-API zum Rendern der Zellen und eine MouseMotionListener, um zu überwachen, welche Zelle markiert ist.

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(); 
     } 
    } 
} 

dieses Beispiel wird das Gitter mit dem Fenster tut Größe ändern, aber es wäre eine triviale Veränderung der Zellen feste Größe zu machen sein.

prüfen 2D Graphics für mehr Details aus

Aktualisierung mit Komponente Beispiel

In diesem Beispiel wird eine Reihe von JPanel s jede Zelle darzustellen.

Jede Zelle ist mit einer festen Breite und Höhe definiert und passt sich nicht mit dem Hauptfenster an.

enter image description here

In diesem Beispiel hat jede Zelle Panel es Hörer eigene Maus ist. Es wäre nicht allzu schwierig, es neu zu codieren, so dass das Hauptfenster einen einzelnen Maus-Listener hätte und stattdessen die Arbeitslast selbst verwaltet.

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

hallo, ich weiß, das ist ein wirklich alter Beitrag. Hey @MadProgrammer, dein Code ist unglaublich!Ich habe es geschnappt, um es für eine Aufgabe, die ich habe, herumzubasteln, aber ich bin ein bisschen pikant, das ist genau das, was ich brauche, aber ich muss das Fenster 1080x760 machen, 1700 Zellen haben und jede Zelle 20x20 machen. Jetzt habe ich das Fenster verkleinert, und ich habe die 1700 Zellen gemacht, das Problem, das ich habe ist, dass, wenn ich versuche, die Zellen auf 20x20 zu verkleinern, der Maushörer verrückt wird und nicht richtig funktioniert ... Ich habe es versucht Ändern der Variablen cellWidth und cellHeight ... aber das funktioniert nicht so gut ... irgendwelche Gedanken? – Twhite1195

+0

@ Twhite1195 Welche Version, die erste oder zweite? – MadProgrammer

+0

@MadProgrammer Zuerst funktionierte das zweite großartig ... bis ich die Zellen in der Größe änderte – Twhite1195

0

Im Mouselistener Beispiel in der Methode mousemoved, möchten Sie vielleicht die xOffset/yOffset obwohl für eine glattere Zellerkennung zu berücksichtigen.

int column = (x - xOffset)/cellWidth; 
int row = (y - yOffset)/cellHeight; 
1

Ich mochte das Rendern von Rahmen nicht, da innerhalb des Gitters einige dupliziert wurden, wenn es mehr als das Beispiel gab. Ich denke, dass diese Lösung ist besser:

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:

Meine Lösung ist besser, denn wenn der ursprüngliche Code 5x5 Zellen sein wird, aber mehr, wie 10x10 ... Innenkanten einiger Zellen wird in Kontakt sein und einige Plätze dickes Gitter erstellen. Es ist schön, auf dem Screenshot zu sehen thick grid

+0

Können Sie Ihre Antwort bearbeiten, um zu erklären, warum Ihre Lösung das Problem löst? –

Verwandte Themen