2016-04-04 11 views
0

私はユーザがJPanelに線を描くことができる描画ツールを開発しています。線を描くときにJPanelに背景グリッドを追加するにはどうすればよいですか?

彼はスタートポイントを選択し、このラインをエンドポイントにドラッグしてラインを作成します。

ここでは、Java Pointクラスを使用して各ポイントの座標を定義しています。

以下

は、このシナリオで使用される単純なコードです:

import java.awt.BasicStroke; 
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.RenderingHints; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class DrawLine extends JPanel { 

    private MouseHandler mouseHandler = new MouseHandler(); 
    private Point p1 = new Point(0, 0); 
    private Point p2 = new Point(0, 0); 
    private boolean drawing; 

    public DrawLine() { 
     this.setPreferredSize(new Dimension(400, 200)); 
     this.addMouseListener(mouseHandler); 
     this.addMouseMotionListener(mouseHandler); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 
     Graphics2D g2d = (Graphics2D) g; 
     g2d.setColor(Color.blue); 
     g2d.setRenderingHint(
      RenderingHints.KEY_ANTIALIASING, 
      RenderingHints.VALUE_ANTIALIAS_ON); 
     g2d.setStroke(new BasicStroke(8, 
      BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); 
     g.drawLine(p1.x, p1.y, p2.x, p2.y); 
    } 

    private class MouseHandler extends MouseAdapter { 

     @Override 
     public void mousePressed(MouseEvent e) { 
      drawing = true; 
      p1 = e.getPoint(); 
      p2 = p1; 
      repaint(); 
     } 

     @Override 
     public void mouseReleased(MouseEvent e) { 
      drawing = false; 
      p2 = e.getPoint(); 
      repaint(); 
     } 

     @Override 
     public void mouseDragged(MouseEvent e) { 
      if (drawing) { 
       p2 = e.getPoint(); 
       repaint(); 
      } 
     } 
    } 

    private void display() { 
     JFrame f = new JFrame("LinePanel"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.add(this); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       new DrawLine().display(); 
      } 
     }); 
    } 
} 

私が何をしたいのか、それぞれの正方形20個のピクセルのグリッドを描画することです。

ユーザーは、たとえば20ピクセルごとに50 cmになるようにスケールをスケールで選択します。

ユーザーがパネル上に描画している間、グリッドはバックグラウンドのままにして、線の寸法をcm単位で判断するために使用する必要があります。

enter image description here

+0

グリッドを特定のサイズにすることは、いくらかの作業を必要とします。私はUIが96dpiでレンダリングされたことを覚えているようだが、それは変更されている可能性があります – MadProgrammer

+0

@MadProgrammer:ありがとう、何をアドバイスしますか? –

+0

私はこれを実行しようとしていますが、画面のPPIを取得するための基本的な計算には、 'sqrt(width^2 + height^2)/対角モニタサイズ(インチ)'が含まれます。見つけにくいことが証明されています。だから、2560x1600'と '22" 'の画面は、 'ReşitDönü[email protected]' 137' – MadProgrammer

答えて

1

あなたはpaintComponent()のすべてのセルを描くことができます:それは明確に、C#で、私は下の図のようにピクチャボックスを使用して、グリッドの背景画像を割り当てられ、その上に描画するために使用されるようにするに

import java.awt.BasicStroke; 
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.RenderingHints; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.util.ArrayList; 

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

public class DrawLine extends JPanel { 

    private MouseHandler mouseHandler = new MouseHandler(); 
    private Point p1 = new Point(0, 0); 
    private Point p2 = new Point(0, 0); 
    private boolean drawing; 

    //Store lines in an arraylist 
    private ArrayList<Line> lines = new ArrayList<>(); 

    public DrawLine() { 
     setBackground(Color.white); 
     this.setPreferredSize(new Dimension(400, 200)); 
     this.addMouseListener(mouseHandler); 
     this.addMouseMotionListener(mouseHandler); 
    } 

    @Override 
    protected void paintComponent(Graphics g) { 
     super.paintComponent(g); 

     //Grid start 
     g.setColor(Color.lightGray); 
     int sideLength = 20; 
     int nRowCount = getHeight()/sideLength; 
     int currentX = sideLength; 
     for (int i = 0; i < nRowCount; i++) { 
      g.drawLine(0, currentX, getWidth(), currentX); 
      currentX = currentX + sideLength; 
     } 

     int nColumnCount = getWidth()/sideLength; 
     int currentY = sideLength; 
     for (int i = 0; i < nColumnCount; i++) { 
      g.drawLine(currentY, 0, currentY, getHeight()); 
      currentY = currentY + sideLength; 
     } 
     //Grid end 

     Graphics2D g2d = (Graphics2D) g; 
     g2d.setColor(Color.blue); 
     g2d.setRenderingHint(
      RenderingHints.KEY_ANTIALIASING, 
      RenderingHints.VALUE_ANTIALIAS_ON); 
     g2d.setStroke(new BasicStroke(8, 
      BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); 
     g.drawLine(p1.x, p1.y, p2.x, p2.y); 

     //draw all previous lines 
     for (int i = 0; i < lines.size(); i++) { 
      g.drawLine(lines.get(i).p1.x, lines.get(i).p1.y, lines.get(i).p2.x, lines.get(i).p2.y); 
     } 
    } 

    private class MouseHandler extends MouseAdapter { 

     @Override 
     public void mousePressed(MouseEvent e) { 
      drawing = true; 
      p1 = e.getPoint(); 
      p2 = p1; 
      repaint(); 
     } 

     @Override 
     public void mouseReleased(MouseEvent e) { 
      drawing = false; 
      p2 = e.getPoint(); 
      repaint(); 
      lines.add(new Line(p1, p2)); 
     } 

     @Override 
     public void mouseDragged(MouseEvent e) { 
      if (drawing) { 
       p2 = e.getPoint(); 
       repaint(); 
      } 
     } 
    } 

    private void display() { 
     JFrame f = new JFrame("LinePanel"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     f.add(this); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       new DrawLine().display(); 
      } 
     }); 
    } 

    public class Line { 
     Point p1; 
     Point p2; 

     public Line(Point p1, Point p2) { 
      this.p1 = p1; 
      this.p2 = p2; 
     } 
    } 
} 
+0

このため私のソリューションは、配列リスト内のすべての以前のラインを維持し、 'paintComponentでそれらのすべてを描いているのに役立ちますありがとうございました'。私の更新されたサンプルを確認してください。 – rdonuk

+0

グレート回答を!ありがとう –

+0

は、あなたは私の単純なコードたい行にユーザーのクリックをさせた後、ウィンドウ内のボタンを使用して、それを削除しますか?または私はこれに別の質問を投稿する必要がありますすることを提供することができます?ありがとう。 –

0

私はこれが最善の解決策であるかどうかわからないんだけど、これは私の仕事:

@Override 
protected void paintComponent(Graphics g) { 
    super.paintComponent(g); 

    // ADDED CODE --- draws horizontal lines --- // 
    for (int i = 1; i < 500; i += 10) { 
     g.drawLine(i, 1, i, 500); 
    } 

    // ADDED CODE --- draws vertical lines --- // 
    for (int i = 1; i < 500; i += 10) { 
     g.drawLine(1, i, 500, i); 
    } 

    Graphics2D g2d = (Graphics2D) g; 
    g2d.setColor(Color.blue); 
    g2d.setRenderingHint(
     RenderingHints.KEY_ANTIALIASING, 
     RenderingHints.VALUE_ANTIALIAS_ON); 
    g2d.setStroke(new BasicStroke(8, 
     BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL)); 

    g.drawLine(p1.x, p1.y, p2.x, p2.y); 
} 

ループの上限として500をハードコーディングするのではなく、JPanelのmaxWidthおよびmaxHeightとして選択する値にすることができます。例えば当たり

1

グリッド内のほとんど正方形の各辺を5cmの寸法を有することになるので、ユーザは4乗を取る線を描く場合、線は20cmの長さを有するであろう。

理論的には、あなたが行くPPI (AKA DPI)計算にPythagorean theoremを使用することができるはずです

ppi = sqrt(wp^2+hp^2)/di 

のようなもの:

  • WPが広いピクセル
  • 馬力の数です高画素数です
  • diはインチの対角サイズですE画面(すなわち、22" )

例えば、22"によって2560x1600の画面は137のPPIを与えます。問題は、スクリーンの対角サイズを得ることです。

あなたがToolkit.getDefaultToolkit().getScreenResolution()を使用できることが示唆されているが、これは 復帰に不正な値が知られているものを行うには、だから、

(私の画面上に、それは102を返します。すなわち、それは137返す必要がある場合)?それ以外の場合は失敗します。

次の例では、96のDPI定義

(非常に古い共通の画面解像度に基づいへのJava/Swingの使用であり、それは今かと言うが、それがあることを使用することはできません)

以下は20cm

Grid

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.DisplayMode; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.GraphicsDevice; 
import java.awt.GraphicsEnvironment; 
import java.awt.Toolkit; 
import java.awt.geom.Rectangle2D; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class Test { 

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

    // The number of CMs per Inch 
    public static final double CM_PER_INCH = 0.393700787d; 
    // The number of Inches per CMs 
    public static final double INCH_PER_CM = 2.545d; 
    // The number of Inches per mm's 
    public static final double INCH_PER_MM = 25.45d; 

    /** 
    * Converts the given pixels to cm's based on the supplied DPI 
    * 
    * @param pixels 
    * @param dpi 
    * @return 
    */ 
    public static double pixelsToCms(double pixels, double dpi) { 
     return inchesToCms(pixels/dpi); 
    } 

    /** 
    * Converts the given cm's to pixels based on the supplied DPI 
    * 
    * @param cms 
    * @param dpi 
    * @return 
    */ 
    public static double cmsToPixel(double cms, double dpi) { 
     return cmToInches(cms) * dpi; 
    } 

    /** 
    * Converts the given cm's to inches 
    * 
    * @param cms 
    * @return 
    */ 
    public static double cmToInches(double cms) { 
     return cms * CM_PER_INCH; 
    } 

    /** 
    * Converts the given inches to cm's 
    * 
    * @param inch 
    * @return 
    */ 
    public static double inchesToCms(double inch) { 
     return inch * INCH_PER_CM; 
    } 

    public static final double SCREEN_DPI = 72.0; 

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

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

    public class TestPane extends JPanel { 

     public TestPane() { 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension((int)Math.round(cmsToPixel(20d, SCREEN_DPI)), (int)Math.round(cmsToPixel(20d, SCREEN_DPI))); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      double cellSize = cmsToPixel(5d, SCREEN_DPI); 
      Rectangle2D cell = new Rectangle2D.Double(0, 0, cellSize, cellSize); 

      g2d.setColor(Color.LIGHT_GRAY); 
      double x = 0; 
      double y = 0; 
      //System.out.println("Columns = " + (getWidth()/cellSize)); 
      //System.out.println("Rows = " + (getHeight()/ cellSize)); 
      while (y + cellSize < getHeight()) { 
       x = 0; 
       while (x + cellSize < getWidth()) { 
        g2d.translate(x, y); 
        g2d.draw(cell); 
        g2d.translate(-x, -y); 
        x += cellSize; 
       } 
       y += cellSize; 
      } 

      g2d.dispose(); 
     } 

    } 
} 

十分があるまであなたは、ウィンドウのサイズを変更すると、グリッドが更新されませんので、注意してくださいかもしれないの合計幅/高さで、5cmx5cmセルのグリッドを定義します新しい行/列のための部屋で、これは意図的にアルゴリズムを示すために行われました。あなたはグリッドは、グリッドを描画while-loop Sを変更することで、ビューの可視境界をオーバーフローさせることができ

...

while (y < getHeight()) { 
    x = 0; 
    while (x < getWidth()) { 
     g2d.translate(x, y); 
     g2d.draw(cell); 
     g2d.translate(-x, -y); 
     x += cellSize; 
    } 
    y += cellSize; 
} 

このすべてのポイントは、あなたが何にSCREEN_DPIを変更することができ、ではありませんあなたが望むものなら、なんでも。印刷プレビューを行いたい場合は、300または72などに変更してください。これは「既知の」値なので、ある解像度から別の解像度に比較的簡単に変換できます。ここで

は、あなたの画面のPPIを計算し、一致し、結果を見てする SCREEN_DPIを変更する考えです。

ありがとう)が、あなたの例では、実際にそれらを表示する行をスケーリングについてですスクリーン上または印刷時の寸法。私が望むのは、センチメートルからピクセルまでのスケールを決定することです。 (数十cmの場合は数cm)、今質問を編集してください。

だから?今、あなたは、その後、基本的には、1cmを表すピクセル数を知る必要がありセンチメートルあたり20個のピクセル

20 pixels per cm

を可能にする測定値を有する例

public static final double SCREEN_DPI = cmsToInches(20); 

のために、一致するように、あなたのSCREEN_DPIを変更cmからピクセルに変換して元に戻すことができます。

1cm = 20ピクセル、2cm = 40ピクセル、3cm = ...など。数学がそのためにどう働くのかがわかるはずです

+0

ありがとうしかし、あなたの例では、画面または印刷時に実際の寸法でそれらを表示する行をスケーリングについてです。私は何をしたいことは、画素センチメートルの規模を決定することである。(20 PXのため数cm)、I編集質問あなたは20個のピクセルpをしたい場合は、今それを確認してください。 –

+0

を@JadChahineさて、あなたは質問しては非常に簡単です、あなただけの、例えば、CMを表すピクセル数を決定する必要がありますセンチえー、それから1センチメートル= 20個のピクセル、2センチメートル= 40個のピクセル...私は今、あなたは、変換がどのように機能するかを見ることができますかなり確信しています – MadProgrammer

関連する問題