2014-03-25 1 views
2

지도의 2D 이미지에서 TCP 소켓 연결을 통해 GPS 좌표를 받아서 그려주는 Java 프로그램을 만듭니다. 생성자는 JFrame과 그래픽 구성 요소를 생성 한 다음 SwingWorker 스레드를 시작하여 소켓에서 좌표를 가져 오는 작업을 처리 한 다음지도에서 수정 사항을 나타내는 타원을 그립니다.스윙 그래픽 객체가 JLabel의 이미지 위에 그려지지 않습니다.

연결을 통해 항상 데이터를 수신 할 수 있지만 프로그램에서 이미지 위에 점을 확실히 그려 내지 못합니다.

의견을 보내 주셔서 감사합니다.

import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.Image; 
import java.io.File; 
import java.util.List; 

import javax.imageio.ImageIO; 
import javax.swing.ImageIcon; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.SwingWorker; 

import connectivity.TelitSocketServer; 
import calculations.PlottingMath; 
import objects.ElephantFix; 

@SuppressWarnings("serial") 
public class Gui 
{ 
    protected JFrame mainWindow; 

    protected JPanel mapArea = new JPanel(); 

    private ReceiveFix rfix; 

    public Gui() 
    { 
     // TODO Auto-generated constructor stub 

     mainWindow = new JFrame(); 

     // Load map image 
     Image map = null; 
     try 
     { 
      File mapImage = new File("map_images/AWE_PLOT.JPG"); 
      map = ImageIO.read(mapImage); 

     } catch (Exception e) 
     { 
      System.out.println(e.toString()); 
     } 



     JLabel label = new JLabel(new ImageIcon(map)); 
     mapArea.add(label); 


     // Map Image Dimensions 

     mainWindow.getContentPane().add(mapArea, "Center"); 

     mainWindow.setSize(471, 670); 
     mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     mainWindow.setTitle("ElePlotter"); 
     mainWindow.setVisible(true); 

     rfix = new ReceiveFix(); 
     rfix.execute(); 

} 

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

} 

private class ReceiveFix extends SwingWorker<Void, ElephantFix> 
{ 

    @Override 
    protected Void doInBackground() 
    { 
     // Start the server 
     String fix = ""; 

     TelitSocketServer currentConnection = new TelitSocketServer(); 
     try 
     { 
      // Wait for client to connect 
      currentConnection.intializeConnection(); 

      while (true) 
      { 
       // Parse and convert received GPS fix into arc radians 
       fix = currentConnection.readLine(); 

       String[] split = fix.split(" "); 


       double latWholeDegrees = Double.parseDouble(split[0] 
         .substring(0, 3)); 
       double longWholeDegrees = Double.parseDouble(split[1] 
         .substring(0, 3)); 

       double latMinutes = Double.parseDouble(split[0] 
         .substring(3)) * .166667; 
       double longMinutes = Double.parseDouble(split[1] 
         .substring(3)) * .166667; 


       double lat = latWholeDegrees - latMinutes/10; 
       double lon = longWholeDegrees + longMinutes/10; 

       publish(new ElephantFix(lat, lon)); 
      } 

     } catch (Exception e) 
     { 

      e.printStackTrace(); 
     } 

     // Return null if somehow unable to publish node data 
     return null; 

    } 


    @Override 
    protected void process(List<ElephantFix> fixes) 
    { 
     int x, y; 
     // Get the most recently published node 
     ElephantFix aFix = fixes.get(fixes.size() - 1); 



     // Translate lat/long into map X/Y pixel 
     x = PlottingMath.getCurrentPixelX(aFix.getLatitude(), 
       aFix.getLongitude()); 
     y = PlottingMath.getCurrentPixelY(aFix.getLatitude(), 
       aFix.getLongitude()); 


     // Plot on image 
     Graphics g = mapArea.getGraphics(); 

     g.setColor(Color.RED); 

     g.fillOval(x, y, 15, 15); 

     // mapArea.validate(); 
     // 
     // mapArea.repaint(); 
     // 
     // Gui.this.repaint(); 

    } 
} 

} 

답변

2

당신은 구성 요소에 getGraphics()를 호출하여 얻은 그래픽 객체 그리기해서는 안 ... 예를 들어, 하나의 구성 요소를 사용하고에 모든 콘텐츠를 렌더링하는 것입니다 . 이렇게하면 지속되지 않는 Graphics 객체와 지속되지 않는 이미지를 얻을 수 있습니다. 대신 Graphics 객체로 BufferedImage를 그려 GUI에 표시하거나 JPanel의 paintComponent 메소드에서 데이터 컬렉션을 반복하여 얻은 데이터로 그립니다.

4

mapArea.getGraphics(); 스윙에서 사용자 정의 페인팅이 수행되지 않습니다.

자세한 내용은 Performing Custom Painting을 살펴보십시오. 컨테이너에 구성 요소를 추가

JLabel label = new JLabel(new ImageIcon(map)); 
mapArea.add(label); 

당신은 뒤로 그이 ... 자식 요소는 항상 용기 색칠 될 것을 보장한다. labelmapArea을 동일한 컨테이너에 추가하는 것이 더 좋을 수도 있습니다.

다음 문제는 그림 구성 요소가 레이블의 맨 위에 위치해야한다는 것입니다. 당신이 할 수이를 위해

...

업데이트를 사용하여 임의의 숫자 이를 달성하기위한 방법으로, 다른 구성 요소를 추가하거나 사용자 정의 페인팅을 수행 할 수있는 레이어 역할을하는 여러 구성 요소를 사용할 수 있습니다.

소리가 나는 것처럼 쉽지 않습니다. 대부분의 레이아웃 관리자는 동일한 공간을 공유하는 두 구성 요소를 고려하지 않습니다. 또한 레이어 간의 연결을 관리해야하므로지도가 가장 낮은 레이어의 가운데에 배치되지만 사용 가능한 공간이지도보다 크거나 작 으면 오프셋이 표류하기 시작합니다 ... 지저분한 ...

A 간단한 해결책은

Map

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Point; 
import java.awt.image.BufferedImage; 
import java.io.IOException; 
import java.util.ArrayList; 
import java.util.List; 
import javax.imageio.ImageIO; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class TestMap { 

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

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

       MapPane pane = new MapPane(); 
       pane.dropPinAt(174, 147); 

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

    public class MapPane extends JPanel { 

     private BufferedImage img; 
     private BufferedImage pin; 
     private List<Point> pins; 

     public MapPane() { 
      pins = new ArrayList<>(25); 
      try { 
       img = ImageIO.read(getClass().getResource("/Map.jpg")); 
       pin = ImageIO.read(getClass().getResource("/Pin.png")); 
      } catch (IOException ex) { 
       ex.printStackTrace(); 
      } 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight()); 
     } 

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

       int x = (getWidth() - img.getWidth())/2; 
       int y = (getHeight() - img.getHeight())/2; 

       g2d.drawImage(img, x, y, this); 

       for (Point p : pins) { 
        // Offset the pin x/y 
        // to allow the point to land on the desired location 
        p.x -= 6; 
        p.y -= 64; 
        System.out.println(p); 
        g2d.drawImage(pin, p.x, p.y, this); 

       } 

       g2d.dispose(); 
      } 
     } 

     protected void dropPinAt(int x, int y) { 
      pins.add(new Point(x, y)); 
     } 
    } 

} 
+0

감사합니다.나는 Swing에 가장 익숙하지 않기 때문에 내 패널을 다른 클래스로 분리하거나 페인트 메서드를 구현하려고 할 때 사용자 정의 페인팅과 관련하여해야할까요? 또한 컨테이너에 대한 마지막 두 점을 정하고 레이블 위에 페인트 구성 요소를 배치 할 수 있습니까? – akibapower711

+0

@ akibapower711 그 결과를 얻기 위해 여러 구성 요소가 필요하다면 – MadProgrammer

+0

이 예제를 고맙게 생각하며 단일 구성 요소 렌더링이 모두 필요한 것입니다. – akibapower711

관련 문제