2015-02-12 57 views
0

我想在兩個JLabel的中心之間畫一條線,當用戶點擊一個標籤時,在另一個標籤上拖動和釋放。無論窗戶的大小是多少,都應該能夠工作。Java繪製組件中心之間的一條線

但行不是中心,我該如何解決它?

以下示例正在工作,但行似乎被JFrame的邊界偏移,因此它們不是中心。

我不想嘗試從點計算中刪除JFrame邊框,因爲真實接口比給出的示例更復雜,並且JFrame中包含更多組件。

我認爲點計算是相對於我使用的JPanel,所以我不會遇到JFrame邊界問題,但似乎並非如此。

非常感謝您的幫助。

import java.awt.Color; 
import java.awt.Component; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.GridLayout; 
import java.awt.Point; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 

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

public class test extends JFrame implements MouseListener { 

    private static JPanel panel = new JPanel(); 
    private static test window = new test(); 

    public test() { 
     panel.setLayout(new GridLayout(2, 2)); 

     JLabel l1 = new JLabel(); 
     JLabel l2 = new JLabel(); 
     JLabel l3 = new JLabel(); 
     JLabel l4 = new JLabel(); 

     l1.setOpaque(true); 
     l2.setOpaque(true); 
     l3.setOpaque(true); 
     l4.setOpaque(true); 

     l1.setBackground(Color.RED); 
     l2.setBackground(Color.BLUE); 
     l3.setBackground(Color.GREEN); 
     l4.setBackground(Color.ORANGE); 

     l1.setName("l1"); 
     l2.setName("l2"); 
     l3.setName("l3"); 
     l4.setName("l4"); 

     panel.add(l1); 
     panel.add(l2); 
     panel.add(l3); 
     panel.add(l4); 

     panel.addMouseListener(this); 

     this.add(panel);  
    } 

    public static void drawArcs(int x1, int y1, int x2, int y2) { 
     Graphics g = window.getGraphics(); 
     Graphics2D g2 = (Graphics2D) g; 
     g2.drawLine(x1, y1, x2, y2); 
    } 

    private static int x1 = 0; 
    private static int y1 = 0; 
    public void mousePressed(MouseEvent e) { 
     Component square1 = panel.getComponentAt(new Point(e.getX(), e.getY())); 
     System.out.println(square1.getName());  
     x1 = square1.getX() + square1.getWidth()/2; 
     y1 = square1.getY() + square1.getHeight()/2; 
    } 

    public void mouseReleased(MouseEvent e) { 
     Component square2 = panel.getComponentAt(new Point(e.getX(), e.getY())); 
     System.out.println(square2.getName());  
     int x2 = square2.getX() + square2.getWidth()/2; 
     int y2 = square2.getY() + square2.getHeight()/2; 
     drawArcs(x1, y1, x2, y2); 
    } 

    @Override 
    public void mouseClicked(MouseEvent arg0) {} 
    @Override 
    public void mouseEntered(MouseEvent arg0) {} 
    @Override 
    public void mouseExited(MouseEvent arg0) {} 

    public static void main(String[] args) { 
     window.setVisible(true); 
     window.setSize(400, 400); 
     window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 


} 
+0

'window.getGraphics();'不是繪畫的工作原理。請參閱[在AWT和Swing中繪畫](http://www.oracle.com/technetwork/java/painting-140037.html)和[執行自定義繪畫](http://docs.oracle.com/javase/tutorial/) uiswing/painting /)瞭解更多詳情 – MadProgrammer 2015-02-12 00:53:33

+0

是的,我知道,但是爲了這個例子,它好像是快速的做法。問題不在於畫線,而是中心問題。 – user1334130 2015-02-12 00:58:33

+1

問題是你正在錯誤地繪畫。您正在使用窗口的圖形對象。如果您正確地繪畫,則Graphics對象將反映相對於面板的適當座標,而不是Window。 – camickr 2015-02-12 01:01:01

回答

2

因此,根本的問題是,你的組件的位置是相對於panel,這是由框架的裝飾偏移,但您使用的是框架現有Graphics背景畫的線,所以線錯位。

除了不使用getGraphics,EVER,您可以通過使用框架的glassPane達到預期的效果,例如

enter image description here

import java.awt.Color; 
import java.awt.Component; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.GridLayout; 
import java.awt.Point; 
import java.awt.Rectangle; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.awt.geom.Line2D; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class Test extends JFrame implements MouseListener { 

    private JPanel panel = new JPanel(); 

    public Test() { 
     ConnectTheDots dots = new ConnectTheDots(); 
     setGlassPane(dots); 
     dots.setVisible(true); 
     panel.setLayout(new GridLayout(2, 2)); 

     panel.add(createLabel(Color.RED)); 
     panel.add(createLabel(Color.BLUE)); 
     panel.add(createLabel(Color.GREEN)); 
     panel.add(createLabel(Color.ORANGE)); 

     panel.addMouseListener(this); 

     this.add(panel); 
    } 

    private Component pressComponent; 
    private Component releaseComponent; 

    public void mousePressed(MouseEvent e) { 
     pressComponent = panel.getComponentAt(new Point(e.getX(), e.getY())); 
    } 

    public void mouseReleased(MouseEvent e) { 
     releaseComponent = panel.getComponentAt(new Point(e.getX(), e.getY())); 
     joinTheDots(); 
    } 

    @Override 
    public void mouseClicked(MouseEvent arg0) { 
    } 

    @Override 
    public void mouseEntered(MouseEvent arg0) { 
    } 

    @Override 
    public void mouseExited(MouseEvent arg0) { 
    } 

    protected void joinTheDots() { 

     Rectangle bounds = pressComponent.getBounds(); 
     Point startPoint = centerOf(bounds); 
     bounds = releaseComponent.getBounds(); 
     Point endPoint = centerOf(bounds); 

     ((ConnectTheDots) getGlassPane()).drawLine(startPoint, endPoint); 

    } 

    protected Point centerOf(Rectangle bounds) { 

     return new Point(
         bounds.x + (bounds.width/2), 
         bounds.y + (bounds.height/2)); 

    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       Test frame = new Test(); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    protected JLabel createLabel(Color background) { 
     JLabel label = new JLabel() { 
      @Override 
      public Dimension getPreferredSize() { 
       return new Dimension(100, 100); 
      } 
     }; 
     label.setOpaque(true); 
     label.setBackground(background); 
     return label; 
    } 

    public class ConnectTheDots extends JPanel { 

     private Point startPoint; 
     private Point endPoint; 

     public ConnectTheDots() { 
      setOpaque(false); 
     } 

     public void drawLine(Point startPoint, Point endPoint) { 
      this.startPoint = startPoint; 
      this.endPoint = endPoint; 
      repaint(); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      if (startPoint != null && endPoint != null) { 
       Graphics2D g2d = (Graphics2D) g.create(); 
       Line2D line = new Line2D.Double(startPoint, endPoint); 
       g2d.setColor(Color.BLACK); 
       g2d.draw(line); 
       g2d.dispose(); 
      } 
     } 

    } 

} 

現在,如果內容覆蓋整個這隻會工作contentPane的可見區域,儘管您可能會將位置信息從一個組件上下文轉換爲另一個組件,但更簡單的解決方案是使用JXLayer

在這種情況下,我會避免重寫paint的原因是Swing組件可以在不需要繪製父組件的情況下進行更新,這可以消除上次繪製父組件時所繪的東西...

看看How to Use Root Panes瞭解更多詳情

+0

哇,這是一個全面的答案,感謝MadProgrammer。 – user1334130 2015-02-12 01:24:24

+0

@ user1334130我至少想知道我的瘋狂想法會起作用...:P – MadProgrammer 2015-02-12 01:25:32

+0

不錯。你是怎麼做出漂亮的小動畫的? – Shannon 2015-02-12 01:26:41