2010-04-01 15 views
9

Mam podklasę JLabel, która stanowi składnik mojego GUI. Zaimplementowałem zdolność przeciągania i upuszczania komponentu z jednego kontenera do drugiego, ale bez żadnych efektów wizualnych. Chcę, aby ten JLabel podążał za kursorem podczas przeciągania elementu z jednego kontenera do drugiego. Pomyślałem, że mogę po prostu stworzyć szklaną szybę i narysować ją tam. Jednak nawet po dodaniu elementu do tafli szkła, ustawić element widoczny, i ustawić taflę szkła widoczną, i ustawić szklaną taflę jako nieprzezroczystą, nadal nie widzę komponentu. Wiem, że komponent działa, ponieważ mogę go dodać do panelu zawartości i pokazać.Umieszczanie składnika na szybie

Jak dodać element do tafli szkła?


W końcu udało się uzyskać prosty przykład działania. Dzięki, @akf. Byłem w stanie zaadaptować to rozwiązanie do mojego pierwotnego problemu, pozwalając mi usunąć ~ 60 linii kodu Java2D, który ręcznie renderował reprezentację JLabel.

package test; 

import java.awt.Color; 

import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.border.LineBorder; 

public class MainFrame extends JFrame { 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     MainFrame mf = new MainFrame(); 
     mf.setSize(400, 400); 
     mf.setLocationRelativeTo(null); 
     mf.setDefaultCloseOperation(DISPOSE_ON_CLOSE); 
     mf.setGlassPane(new JPanel()); 

     JLabel l = new JLabel(); 
     l.setText("Hello"); 
     l.setBorder(new LineBorder(Color.BLACK, 1)); 
     l.setBounds(10, 10, 50, 20); 
     l.setBackground(Color.RED); 
     l.setOpaque(true); 
     l.setPreferredSize(l.getSize()); 

     //mf.add(l); 
     ((JPanel)mf.getGlassPane()).add(l); 
     mf.getGlassPane().setVisible(true); 

     mf.setVisible(true); 
    } 
} 
+0

Czy próbowałeś ustawiania składnik AS na glasspane zamiast dodawania go do glasspane? – willcodejavaforfood

+0

Ten komponent reprezentuje kafelek w grze słowno-obrazkowej, więc jest to tylko 37 * 37 i używa granic dla efektu. Nie rozumiem, jak mógłbym to przekształcić w szklaną taflę, ponieważ byłby bałagan z wymiarami płytki. –

+0

Czy możemy zobaczyć kod? W szczególności sposób dodawania składnika do tafli szkła i ustawiania go jako widocznego. –

Odpowiedz

3

Poza wskazówkami do już podanych przykładów LayerPane, problem z oryginalnym kodem koncentruje się wokół ustawienia preferowanego rozmiaru etykiety. Ustawiasz go, zanim rozmiar JLabel będzie większy, więc:

l.setPreferredSize(l.getSize()); 

jest nieskuteczny. Jeśli, z drugiej strony, wykonasz to połączenie po zadzwonieniu pod numer setBounds, zobaczysz żądane wyniki. Mając to na uwadze, to kolejność:

l.setPreferredSize(l.getSize()); 
l.setBounds(10, 10, 50, 20); 

wyglądać tak:

l.setBounds(10, 10, 50, 20); 
l.setPreferredSize(l.getSize()); 
13

Poniższy przykładowy kod pokazuje, jak przeciągnąć kawałek szachownicy wokół szachownicy. Używa JLayeredPane zamiast tafli szkła, ale jestem pewien, że koncepcje byłyby takie same. To jest:

a) dodaje się szybę do okna głównego
b) zawiera taflę szkła w zakresie widzialnym
c) dodania składnika do szyby upewniając granice są ważne
d) stosowanie setLocation () animowanie przeciąganie komponentu

Edycja: dodano kod naprawić SSCCE

JLabel l = new JLabel(); 
l.setText("Hello"); 
l.setBorder(new LineBorder(Color.BLACK, 1)); 
// l.setPreferredSize(l.getSize()); 
// l.setBounds(10, 10, 50, 20); 
((JPanel)mf.getGlassPane()).add(l); 

mf.setVisible(true); 
mf.getGlassPane().setVisible(true); 

Przy zastosowaniu układu menedżerów nigdy nie używać setSize() lub setBounds() metody. W twoim przypadku wystarczy ustawić preferowany rozmiar na (0, 0), ponieważ jest to domyślny rozmiar wszystkich składników.

Działa po dodaniu etykiety do ramki, ponieważ domyślnym układem arkusza zawartości w ramce jest układ krawędzi, dlatego preferowany rozmiar etykiety jest ignorowany, a etykieta ma rozmiar ramki .

Jednak domyślnie JPanel używa FlowLayout, który respektuje preferowany rozmiar komponentu. Ponieważ preferowany rozmiar to 0, nie ma niczego do malowania.

Również szyba musi być widoczna, aby mogła zostać pomalowana.

Proponuję przeczytać Swing tutorial. Są tam informacje o tym, jak działają menedżerowie layoutów i o tym, jak działają tafle szkła, a każda sekcja ma przykłady robocze.

Edit: Przykładowy kod dodany poniżej:

import java.awt.*; 
import java.awt.event.*; 
import java.util.*; 
import javax.swing.*; 

public class ChessBoard extends JFrame implements MouseListener, MouseMotionListener 
{ 
    JLayeredPane layeredPane; 
    JPanel chessBoard; 
    JLabel chessPiece; 
    int xAdjustment; 
    int yAdjustment; 

    public ChessBoard() 
    { 
     Dimension boardSize = new Dimension(600, 600); 

     // Use a Layered Pane for this this application 

     layeredPane = new JLayeredPane(); 
     layeredPane.setPreferredSize(boardSize); 
     layeredPane.addMouseListener(this); 
     layeredPane.addMouseMotionListener(this); 
     getContentPane().add(layeredPane); 

     // Add a chess board to the Layered Pane 

     chessBoard = new JPanel(); 
     chessBoard.setLayout(new GridLayout(8, 8)); 
     chessBoard.setPreferredSize(boardSize); 
     chessBoard.setBounds(0, 0, boardSize.width, boardSize.height); 
     layeredPane.add(chessBoard, JLayeredPane.DEFAULT_LAYER); 

     // Build the Chess Board squares 

     for (int i = 0; i < 8; i++) 
     { 
      for (int j = 0; j < 8; j++) 
      { 
       JPanel square = new JPanel(new BorderLayout()); 
       square.setBackground((i + j) % 2 == 0 ? Color.red : Color.white); 
       chessBoard.add(square); 
      } 
     } 

     // Add a few pieces to the board 

     ImageIcon duke = new ImageIcon("dukewavered.gif"); // add an image here 

     JLabel piece = new JLabel(duke); 
     JPanel panel = (JPanel)chessBoard.getComponent(0); 
     panel.add(piece); 
     piece = new JLabel(duke); 
     panel = (JPanel)chessBoard.getComponent(15); 
     panel.add(piece); 
    } 

    /* 
    ** Add the selected chess piece to the dragging layer so it can be moved 
    */ 
    public void mousePressed(MouseEvent e) 
    { 
     chessPiece = null; 
     Component c = chessBoard.findComponentAt(e.getX(), e.getY()); 

     if (c instanceof JPanel) return; 

     Point parentLocation = c.getParent().getLocation(); 
     xAdjustment = parentLocation.x - e.getX(); 
     yAdjustment = parentLocation.y - e.getY(); 
     chessPiece = (JLabel)c; 
     chessPiece.setLocation(e.getX() + xAdjustment, e.getY() + yAdjustment); 

     layeredPane.add(chessPiece, JLayeredPane.DRAG_LAYER); 
     layeredPane.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); 
    } 

    /* 
    ** Move the chess piece around 
    */ 
    public void mouseDragged(MouseEvent me) 
    { 
     if (chessPiece == null) return; 

     // The drag location should be within the bounds of the chess board 

     int x = me.getX() + xAdjustment; 
     int xMax = layeredPane.getWidth() - chessPiece.getWidth(); 
     x = Math.min(x, xMax); 
     x = Math.max(x, 0); 

     int y = me.getY() + yAdjustment; 
     int yMax = layeredPane.getHeight() - chessPiece.getHeight(); 
     y = Math.min(y, yMax); 
     y = Math.max(y, 0); 

     chessPiece.setLocation(x, y); 
    } 

    /* 
    ** Drop the chess piece back onto the chess board 
    */ 
    public void mouseReleased(MouseEvent e) 
    { 
     layeredPane.setCursor(null); 

     if (chessPiece == null) return; 

     // Make sure the chess piece is no longer painted on the layered pane 

     chessPiece.setVisible(false); 
     layeredPane.remove(chessPiece); 
     chessPiece.setVisible(true); 

     // The drop location should be within the bounds of the chess board 

     int xMax = layeredPane.getWidth() - chessPiece.getWidth(); 
     int x = Math.min(e.getX(), xMax); 
     x = Math.max(x, 0); 

     int yMax = layeredPane.getHeight() - chessPiece.getHeight(); 
     int y = Math.min(e.getY(), yMax); 
     y = Math.max(y, 0); 

     Component c = chessBoard.findComponentAt(x, y); 

     if (c instanceof JLabel) 
     { 
      Container parent = c.getParent(); 
      parent.remove(0); 
      parent.add(chessPiece); 
      parent.validate(); 
     } 
     else 
     { 
      Container parent = (Container)c; 
      parent.add(chessPiece); 
      parent.validate(); 
     } 
    } 

    public void mouseClicked(MouseEvent e) {} 
    public void mouseMoved(MouseEvent e) {} 
    public void mouseEntered(MouseEvent e) {} 
    public void mouseExited(MouseEvent e) {} 

    public static void main(String[] args) 
    { 
     JFrame frame = new ChessBoard(); 
     frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE); 
     frame.setResizable(false); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 
} 
+0

Mam problem z przełączaniem JLayeredPane, ponieważ używam GridBagLayout do układu głównego formularza. Dzieje się to z DRAG_LAYER, ponieważ wymagane jest posiadanie tego samego menedżera układu co reszta panelu treści, ale nie chcę menedżera układu, ponieważ będzie on używany tylko do przeciągania. –

+0

Mój przykład używa GridLayout, a DRAG_LAYER nie musi używać tego samego menedżera układu. W rzeczywistości nie używa on menedżerów układu, ponieważ ręcznie pozycjonuje komponenty. Nie sugeruję, że powinieneś korzystać z warstwy tylko warstwowej, że koncepcje powinny być takie same. Dzieje się tak, ponieważ szklana tafla również nie używa menedżera układu, który jest odpowiedzialny za prawidłowe ustawienie granic komponentu. W każdym razie nie mogę pomóc dalej. Dałem ci działający kod, nie wiem jak twój kod jest inny. – camickr

+3

Rozpocznij od utworzenia prostego SSCCE (http://sscce.org), które wyświetla szklaną szybę z JLabel w określonej pozycji. Kiedy już to opanujesz, przejdziesz do animacji położenia etykiety podczas przeciągania myszą. Jeśli nie możesz uruchomić SSCCE, masz prosty kod do opublikowania, a my możemy podać bardziej konkretne sugestie. – camickr

3

Odkąd został po blogach Romain facet na huśtawce na długi czas. Mam link, który może Cię zainteresować. Wydał źródło - które używało GlassPane do efektów DnD.

http://jroller.com/gfx/entry/drag_and_drop_effects_the

nigdy się nie używać gazowany animacja/wpływ na DnD, więc nie mogę wypowiedzieć się dalej: - |

+0

Niestety, wykorzystuje to obrazy rysowane bezpośrednio na tafli szkła, a nie komponenty renderowane przez Swing. –

+0

Nie ma znaczenia, że ​​przykład rysuje obrazy. Aby użyć komponentów, po prostu dodaj komponent do szyby i upewnij się, że ustawiłeś granice prawidłowo. – camickr

+0

Problem polegał na tym, że dodawałem komponent do tafli szkła i ustalałem jej granice, ale wciąż nie było wyświetlane. Jedyne, co mogę sobie wyobrazić, to to, że nie mam pojęcia, jak poprawnie ustawić granice na komponencie. –

11

Chociaż styczna do pytaniu JLayeredPaneexample cytowany przez @camickr przyznaje następujące adaptację, która podkreśla efekt mouseReleased() nad istniejącego komponentu.

public ChessBoard() { 
    ... 
    // Add a few pieces to the board 
    addPiece(3, 0, "♛"); 
    addPiece(4, 0, "♚"); 
    addPiece(3, 7, "♕"); 
    addPiece(4, 7, "♔"); 
} 

static Font font = new Font("Sans", Font.PLAIN, 72); 

private void addPiece(int col, int row, String glyph) { 
    JLabel piece = new JLabel(glyph, JLabel.CENTER); 
    piece.setFont(font); 
    JPanel panel = (JPanel) chessBoard.getComponent(col + row * 8); 
    panel.add(piece); 
} 
+0

@DavidKroukamp: Więcej na temat dostosowywania glifów [tutaj] (http://stackoverflow.com/q/18686199/230513). – trashgod