2017-11-28 4 views
0

Ich habe ein Board 14x14, das JButtons hat und jedes Jbutton hat eine andere Farbe. Wenn Sie auf eine dieser Schaltflächen klicken, werden die Nachbarn mit derselben Farbe überprüft und entfernt. Wenn es entfernt wird, gibt es einen leeren Platz zwischen der Tafel, so dass die oben genannten Tasten, nach unten gehen sollten, um den leeren Raum zu füllen. Ich habe es mit GridLayout versucht, aber ich weiß nicht, wie ich die obigen Tasten bewegen soll.Welches Swing-Layout sollte ich verwenden, um JButtons zu bewegen

Antwort

0

Sie könnten versuchen, einen 2-dimensionalen Array von JButtons mit

JButton[][] buttons = new JButton[14][14]; 

for (int i=0; i < buttons.length; i++) { 
for (int j=0; j < buttons[i].length; j++) { 
    buttons[i][j] = new JButton("Button [" + i + "][" + j + "]"); 
} 
} 

// Then do whatever,remove,change color,check next element in array 
// and compare colors etc 
buttons[2][3].setText("changed text"); 
0

Wenn Sie die oben genannten Tasten wollen mehr Platz nehmen Sie den leeren Raum zu füllen, wenn Sie eine Komponente gut entfernen, ist dies nicht möglich ist, GridLayout mit , aber Sie können einige leere Komponenten wie JLabels hinzufügen, um den Raum zu füllen.

Sie können eine Komponente in einem Container zu einem bestimmten Index für diesen Zweck hinzufügen, indem Sie die Containeradd (Component comp, int index) Methode verwenden.

Dieses Codefragment einen Knopf an einem angegebenen Index (45, nur zum Beispiel) mit einem leeren Komponente in einer Platte ersetzt, die einen GridLayout gesetzt:

JPanel boardPanel = new JPanel (new GridLayout (14, 14)); 

// ... add your buttons ... 

// This code could be invoked inside an ActionListener ... 

boardPanel.remove (45); 
boardPanel.add (new JLabel (""), 45); 
boardPanel.revalidate(); 
boardPanel.repaint(); 

diese Weise wird der Rest der Komponenten bewegt sich nicht und Sie sehen nur einen leeren Platz, der Ihre Schaltfläche ersetzt.

Sie können mehr erreichen: Wenn Sie die leere Beschriftung bei Index = 0 hinzufügen, werden alle Schaltflächen nach rechts verschoben (denken Sie daran, dass sich die Anzahl der Komponenten nicht ändern sollte, da sonst die Größe der Komponenten geändert wird)) und so weiter, können Sie eine einzelne Komponente "verschieben", indem Sie sie einfach entfernen und zu einem anderen Index hinzufügen. Ein anderer Weg zu gehen wäre, ein 2-dimensionales Array von Objekten zu speichern, die Ihre Modelllogik repräsentieren (Sie können Farbe und all die Dinge speichern, die Sie benötigen) und sie selbst malen, indem Sie die paintComponent-Methode überschreiben. Als Beispiel für einen benutzerdefinierten Malansatz sehen Sie sich this MadProgrammer's answer an, wo er zeigt, wie man eine bestimmte Zelle in einem Gitter hervorhebt (in diesem Fall verwendet er eine Liste zum Speichern von Objekten, aber ein 2D-Array funktioniert als Gut).

1

Dies ist tatsächlich ein Fall, in dem Sie kaum einen Layout-Manager überhaupt verwenden können.

Ein LayoutManager soll das Layout von alle Komponenten auf einmal berechnen. Es wird von bestimmten Ereignissen ausgelöst (z. B. wenn die Größe der übergeordneten Komponente geändert wird). Dann berechnet es das Layout und ordnet die untergeordneten Komponenten entsprechend an.

In Ihrem Fall ist die Situation ganz anders. Es gibt keinen Layout-Manager, der den Zustand "intermediär", der erscheint, sinnvoll darstellen kann, während die oberen Tasten herunterfallen. Während die Komponenten animiert sind, können sie nicht Teil eines ordnungsgemäßen Layouts sein.

Die Animation selbst mag auch etwas knifflig sein, kann aber glücklicherweise generisch gelöst werden. Aber Sie müssen immer noch die Informationen über verfolgen, wobei jede Komponente (d. H. Jede Schaltfläche) sich derzeit im Raster befindet. Wenn eine Schaltfläche entfernt wird, müssen Sie die Schaltflächen berechnen, die davon betroffen sind (nämlich die direkt darüber liegenden). Diese müssen animiert werden. Nach der Animation müssen Sie diesen Schaltflächen die neuen Gitterkoordinaten zuweisen.

Das folgende ist ein MCVE, das einen grundlegenden Ansatz zeigt. Es entfernt einfach die Schaltfläche, auf die geklickt wurde, aber es sollte einfach zu verallgemeinern sein, um andere Schaltflächen basierend auf anderen Bedingungen zu entfernen.

import java.awt.Point; 
import java.awt.Rectangle; 
import java.awt.event.ComponentAdapter; 
import java.awt.event.ComponentEvent; 
import java.util.ArrayList; 
import java.util.List; 

import javax.swing.JButton; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

public class FallingButtons 
{ 
    public static void main(String[] args) 
    { 
     SwingUtilities.invokeLater(() -> createAndShowGui()); 
    } 

    private static void createAndShowGui() 
    { 
     JFrame f = new JFrame(); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     int rows = 8; 
     int cols = 8; 
     GridPanel gridPanel = new GridPanel(rows, cols); 
     for (int r=0; r<rows; r++) 
     { 
      for (int c=0; c<cols; c++) 
      { 
       JButton button = new JButton(r+","+c); 
       gridPanel.addComponentInGrid(r, c, button); 

       button.addActionListener(e -> 
       { 
        Point coordinates = gridPanel.getCoordinatesInGrid(button); 
        if (coordinates != null) 
        { 
         gridPanel.removeComponentInGrid(
          coordinates.x, coordinates.y); 
        } 
       }); 
      } 
     } 
     f.getContentPane().add(gridPanel); 

     f.setSize(500, 500); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 
} 

class GridPanel extends JPanel 
{ 
    private final int rows; 
    private final int cols; 
    private final JComponent components[][]; 

    GridPanel(int rows, int cols) 
    { 
     super(null); 
     this.rows = rows; 
     this.cols = cols; 
     this.components = new JComponent[rows][cols]; 

     addComponentListener(new ComponentAdapter() 
     { 
      @Override 
      public void componentResized(ComponentEvent e) 
      { 
       layoutGrid(); 
      } 
     }); 
    } 

    private void layoutGrid() 
    { 
     int cellWidth = getWidth()/cols; 
     int cellHeight = getHeight()/rows; 
     for (int r=0; r<rows; r++) 
     { 
      for (int c=0; c<cols; c++) 
      { 
       JComponent component = components[r][c]; 
       if (component != null) 
       { 
        component.setBounds(
         c * cellWidth, r * cellHeight, cellWidth, cellHeight); 
       } 
      } 
     } 
    } 

    Point getCoordinatesInGrid(JComponent component) 
    { 
     for (int r=0; r<rows; r++) 
     { 
      for (int c=0; c<cols; c++) 
      { 
       if (components[r][c] == component) 
       { 
        return new Point(r, c); 
       } 
      } 
     } 
     return null; 
    } 

    void addComponentInGrid(int row, int col, JComponent component) 
    { 
     add(component); 
     components[row][col] = component; 
     layoutGrid(); 
    } 

    JComponent getComponentInGrid(int row, int col) 
    { 
     return components[row][col]; 
    } 

    void removeComponentInGrid(int row, int col) 
    { 
     remove(components[row][col]); 
     components[row][col] = null; 

     List<Runnable> animations = new ArrayList<Runnable>(); 
     for (int r=row-1; r>=0; r--) 
     { 
      JComponent component = components[r][col]; 
      if (component != null) 
      { 
       Runnable animation = 
        createAnimation(component, r, col, r + 1, col); 
       animations.add(animation); 
      } 
     } 
     for (Runnable animation : animations) 
     { 
      Thread t = new Thread(animation); 
      t.setDaemon(true); 
      t.start(); 
     } 
     repaint(); 
    } 

    private Runnable createAnimation(JComponent component, 
     int sourceRow, int sourceCol, int targetRow, int targetCol) 
    { 
     int cellWidth = getWidth()/cols; 
     int cellHeight = getHeight()/rows; 
     Rectangle sourceBounds = new Rectangle(
      sourceCol * cellWidth, sourceRow * cellHeight, 
      cellWidth, cellHeight); 
     Rectangle targetBounds = new Rectangle(
      targetCol * cellWidth, targetRow * cellHeight, 
      cellWidth, cellHeight); 
     Runnable movement = createAnimation(
      component, sourceBounds, targetBounds); 
     return() -> 
     { 
      components[sourceRow][sourceCol] = null; 
      movement.run(); 
      components[targetRow][targetCol] = component; 
      repaint(); 
     }; 
    } 


    private static Runnable createAnimation(JComponent component, 
     Rectangle sourceBounds, Rectangle targetBounds) 
    { 
     int delayMs = 10; 
     int steps = 20; 
     Runnable r =() -> 
     { 
      int x0 = sourceBounds.x; 
      int y0 = sourceBounds.y; 
      int w0 = sourceBounds.width; 
      int h0 = sourceBounds.height; 

      int x1 = targetBounds.x; 
      int y1 = targetBounds.y; 
      int w1 = targetBounds.width; 
      int h1 = targetBounds.height; 

      int dx = x1 - x0; 
      int dy = y1 - y0; 
      int dw = w1 - w0; 
      int dh = h1 - h0; 

      for (int i=0; i<steps; i++) 
      { 
       double alpha = (double)i/(steps - 1); 

       int x = (int)(x0 + dx * alpha); 
       int y = (int)(y0 + dy * alpha); 
       int w = (int)(w0 + dw * alpha); 
       int h = (int)(h0 + dh * alpha); 
       SwingUtilities.invokeLater(() -> 
       { 
        component.setBounds(x, y, w, h); 
       }); 
       try 
       { 
        Thread.sleep(delayMs); 
       } 
       catch (InterruptedException e) 
       { 
        Thread.currentThread().interrupt(); 
        return; 
       } 
      } 
      SwingUtilities.invokeLater(() -> 
      { 
       component.setBounds(x1, y1, w1, h1); 
      }); 
     }; 
     return r; 
    } 



} 
Verwandte Themen