2009-08-02 4 views
2

私のプログラムでは、さまざまなJComponents(一般的にはJPanels)を印刷する必要があります。私は今それを行う方法は、次のコードを使用することです:JPanelを元の位置から取り除かずに印刷するための準備を整える

g2d.scale(pf.getImageableWidth()/componentToPrint.getWidth(), pf.getImageableHeight()/componentToPrint.getHeight()); 

をしかし、これは多くの場合、おそらく、伸びあるいは私が印刷しようとしているものは何でも変形し、私は非常にインテリジェントサイズの再何かをすることを好みます

componentToPrint.setSize(pf.ImageableWidth(), pf.ImageableHeight); 

または新しいJFrameの中に成分を添加した後、フレームサイズを設定すると言う(問題コンポーネントは一度に2つの場所に存在することができないです)の機能バージョン。私は、リサイズがGUIの残りの部分をひどく見えるようにするかどうかは気にしません。それは、簡単にリセットできるものである限りです。

これを行う方法はありますか?

答えて

0

私はあなた自身の質問に答えたと思います。各コンポーネントにはメソッドがあります:

setSize(int width, int height); 
+1

コンポーネントはレイアウトマネージャの制御下にあり、したがって、独自のサイズを制御することはできません。それを呼び出すことは何もしません。 –

1

私が思うに、問題はスケール操作とは関係がないと思います。あなたの論理は間違っています。 Imageableのスケールとコンポーネントのスケールが同じではないため、ほとんどの場合xとyのスケールは異なります。これが、スケール操作後にコンポーネントが歪んでいる理由です。

double factorX = pf.getImageableWidth()/component.getWidth(); 
double factorY = pf.getImageableHeight()/component.getHeight(); 
double factor = Math.min(factorX, factorY); 
g2.scale(factor,factor); 

その後、新しいサイズに従って画像を適切な座標に翻訳することができます。 は/任意の幅で、私は任意のGraphicsオブジェクトに描画することができ、そのパネル内の公開/パッケージ保護法にJPanelの実装のpaintComponent()方法のうち、描画コードをリファクタリングでしょう

+0

それほどではありません。問題はアスペクト比だけではありません。私のGUIの大部分は、GridBagLayoutに大きく依存しています。GridBagLayoutは、コンポーネントをインテリジェントにサイズ変更して、コンポーネントをスペースに最適にフィットさせます。たとえば、最大化するとオブジェクト間のギャップが大きくなり、縮小するとテキストが短くカットされる可能性があります。また、イメージベースのスケーリングは、インテリジェントなコンポーネントのサイズ変更とは対照的に、品質を低下させることになります。 –

+0

私はGridBagLayoutに関してあなたが言ったことを理解していますが、スケーリングについて何に同意していません。この場合、それはイメージスケーリングではなく、実行前にグラフィカル操作に適用されるAffineTransformです。したがって、品質の損失はまったくありません。 –

+0

それは良い点です、私はそれがどのように縮尺を確認しませんでした。それにもかかわらず、画質に一貫性があっても、そのような種類のスケーリングは、(画面上のアスペクト比に応じて)一貫性のない印刷を行い、プリントスペースに必ずしも最適に表示されるとは限らない。 –

1

...それがお役に立てば幸い高さ(おそらく描画コードは一般的です)。

この例は、いくつかの描画ロジック(大きなX、パネルのサイズ)を持つパネルを含むフレームを持っています。この例の主な方法は、画像のサイズがパネルのサイズと異なる場合でも、画像を取得してファイルに書き込む方法を示しています。


import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.image.BufferedImage; 
import java.io.File; 

import javax.imageio.ImageIO; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 

public class MockFrame extends JFrame { 

    // throws Exception, as just an example (not really advised to do this) 
    public static void main(String[] args) throws Exception { 
     MockFrame frame = new MockFrame(); 
     frame.setVisible(true); 

     // different sizes from the frame 
     int WIDTH = 500; 
     int HEIGHT = 500; 

     BufferedImage b = new BufferedImage(WIDTH, HEIGHT, 
      BufferedImage.TYPE_INT_ARGB); 

     Graphics2D g2d = (Graphics2D) b.getGraphics(); 

     // should set some background, as the panel's background 
     // is dealt with by super.paintComponent() 
     g2d.setBackground(Color.white); 

     frame.getPanel().drawingLogic(b.getGraphics(), WIDTH, HEIGHT); 

     ImageIO.write(b, "png", new File("test.png")); 

    } 

    private MockPanel panel; 

    public MockFrame() { 
     this.setSize(200, 200); 
     this.setDefaultCloseOperation(EXIT_ON_CLOSE); 

     panel = new MockPanel(); 
     getContentPane().add(panel); 
    } 

    public MockPanel getPanel() { 
     return panel; 
    } 

    private class MockPanel extends JPanel { 

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

     drawingLogic(g, getWidth(), getHeight()); 
    } 

    public void drawingLogic(Graphics g, int width, int height) { 
     g.setColor(Color.black); 

     g.drawLine(0, 0, width, height); 
     g.drawLine(0, height, width, 0); 
    } 
    } 
} 

これにより、GUIの外部にあるオブジェクトが描画アルゴリズムにフックできるようになります。私が見る1つの欠点は、パネルを実際に実装するためにパネルを印刷したいオブジェクト間の依存関係を作成することです。しかし、それは(私はそれを試してみましたが、いくつかの問題を持っていると思われている、まだその場でパネルのサイズを変更するよりはましだ - 私はそれが伝播するsetSize()変更のためのいくつかの時間がかかると思います

EDIT:

受けて私は上記のコードスニペットの修正版を提供しました。おそらくそれを行う最良の方法ではなく、あまりユーザーフレンドリーではありません(はエンドユーザーアプリケーションでを使用しません)。レイアウトマネージャのルールに従ってフレーム内のすべてのサイズを変更します。


/* This code snippet describes a way to resize a frame for printing at 
* a custom size and then resize it back. 
* 
* Copyright (C) 
* 
* This program is free software: you can redistribute it and/or modify 
* it under the terms of the GNU General Public License as published by 
* the Free Software Foundation, either version 3 of the License, or 
* (at your option) any later version. 
* 
* This program is distributed in the hope that it will be useful, 
* but WITHOUT ANY WARRANTY; without even the implied warranty of 
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
* GNU General Public License for more details. 
* 
* You should have received a copy of the GNU General Public License 
* along with this program. If not, see . 
*/ 

import java.awt.Container; 
import java.awt.Graphics2D; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.Insets; 
import java.awt.image.BufferedImage; 
import java.io.File; 

import javax.imageio.ImageIO; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JOptionPane; 

public class MockFrame extends JFrame { 

    // throws Exception, as just an example (not really advised to do this) 
    public static void main(String[] args) throws Exception { 
     final MockFrame frame = new MockFrame(); 
     frame.setVisible(true); 

     // different sizes from the frame 
     final int WIDTH = 500; 
     final int HEIGHT = 700; 

     final BufferedImage b = new BufferedImage(WIDTH, HEIGHT, 
       BufferedImage.TYPE_INT_ARGB); 

     final Graphics2D g2d = (Graphics2D) b.getGraphics(); 

     final int previousWidth = frame.getWidth(); 
     final int previousHeight = frame.getHeight(); 

     frame.setSize(WIDTH, HEIGHT); 
     frame.repaint(); 

     JOptionPane.showMessageDialog(null, 
       "Press OK when the window has finished resizing"); 

     frame.print(g2d); 
     frame.setSize(previousWidth, previousHeight); 
     ImageIO.write(b, "png", new File("test.png")); 

    } 

    public MockFrame() { 
     this.setSize(200, 200); 
     this.setDefaultCloseOperation(EXIT_ON_CLOSE); 

     boolean shouldFill = true; 
     boolean shouldWeightX = true; 

     Container pane = getContentPane(); 

     // code from 
     // http://java.sun.com/docs/books/tutorial/uiswing/layout/gridbag.html 
     // just to add some components in the frame... :) 
     // left out in here for brevity 

    } 

} 

コードは、基本的に、フレームのサイズを変更し再描画が完了するまでスレッドがブロックできるようにユーザに確認メッセージを示している(Thread.sleep()によって行うことができ、それはメッセージを使用して、より透明'S)。次に、フレームを印刷し、元の形状に戻します。少しハッキーですが、それは動作します。

-- Flaviu Cipcigan

+0

それは私が探しているものですが、どうやってこの作業をすることができるのか分かりません。すべてのペイントロジックは、すべてのSwingコンポーネントであるため、継承されたペイントメソッドからのものです。私のコードでは何も描画されません。すべてのコードは、コンポーネントの実際のサイズに基づいてペイントするため、コンポーネントの実際のサイズを変更することなく、ペイント方法を変更することはできません。 –

+0

あなたのコメントに対する改訂された回答については、上記の編集済みの記事を参照してください。乾杯! –

+0

これは私がやりたいことですが、ランダムに選択されたComponentはレイアウトマネージャによって制御される可能性が高いので、setSize()メソッドは何もしません。 –

2

私は、あなたが探しているソリューションは、所望のコンテンツを含む新しいJPanelのを構築するために、代わりにコピーを印刷することだと思います。 CellRendererPaneを使用すると、探しているように正確なサイズ変更動作が得られます。

JComponentsが合理的によく書かれている場合は、新しく新しいものを作成し、そのモデルを元のものと同じに設定することは問題ではありません。

CellRendererPane cellRendererPane = new CellRendererPane(); 
// It's important to add the cell renderer pane to something 
// you can use the same one for all of your exporting if you like and just 
// add it to your main frame's content pane - it won't show up anywhere. 
add(cellRendererPane); 

JPanel printPanel = createCopy(panel); 
cellRendererPane.paintComponent(g, printPanel, null, 0, 0, exportDim.width, exportDim.height, true); 

完全な実例があります。 createPanel()メソッドは、レンダリングするコンポーネントを作成する必要があります。実際の例では、使い捨てコンポーネントの新しいモデルを再作成するのではなく、同じモデルを使用する必要があります。

public class SCCE { 

    public static void main(String[] args) throws Exception { 
     UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
     final JFrame f = new JFrame("SCCE"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 


     f.getContentPane().setLayout(new BorderLayout()); 
     f.getContentPane().add(SCCE.createPanel()); 

     final CellRendererPane backgroundRenderer = new CellRendererPane(); 

     // Add the renderer somewhere where it won't be seen 
     f.getContentPane().add(backgroundRenderer, BorderLayout.NORTH); 
     f.getContentPane().add(createSaveButton(backgroundRenderer), BorderLayout.SOUTH); 

     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

    // Create your custom component from whatever model here.. 
    private static final Component createPanel() { 
     DefaultListModel model = new DefaultListModel(); 
     for (int i = 0; i < 10; i++) { 
      model.addElement("Item number " + i); 
     } 
     return new JList(model); 
    } 

    private static JButton createSaveButton(final CellRendererPane backgroundRenderer) { 
     return new JButton(new AbstractAction("Save image to file") { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       Dimension d = new Dimension(400, 300); 

       BufferedImage img = new BufferedImage(d.width, d.height, BufferedImage.TYPE_INT_ARGB); 
       Graphics2D g = img.createGraphics(); 
       backgroundRenderer.paintComponent(g, createPanel(), null, 0, 0, d.width, d.height, true); 
       g.dispose(); 

       try { 
        File output = new File("test.png"); 
        System.err.println("Saved to " + output.getAbsolutePath()); 
        ImageIO.write(img, "png", output); 
       } catch (IOException ex) { 
        ex.printStackTrace(); 
       } 
      } 
     }); 
    } 

} 
関連する問題