2011-12-06 101 views
0

我有一個應用程序,其圖形被認爲以1024x768顯示。java JFrame使用虛擬繪圖空間縮放UI顯示

我想在大小靈活應用無需重寫所有的繪圖代碼,位置計算等。

爲了實現我試圖重寫的JFrame容器的paint方法以下列方式:

@Override 
public void paint(Graphics g) 
{ 
    BufferedImage img = new BufferedImage(this.desiredWidth, this.desiredHeight, BufferedImage.TYPE_INT_ARGB); 

    Graphics2D gi = (Graphics2D) img.getGraphics(); 
    gi.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB); 
    gi.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
    gi.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); 

    super.paint(gi); 
    gi.dispose(); 

    ((Graphics2D) g).drawImage(img, screenScale, null); 

} 

screenScale是我在構造函數中創建的AffineTransform對象,它根據目標大小進行適當的縮放。

現在的問題是:我的子組件會被繪製和縮放,但是會受到父JFrame的限制。因此,如果我的父框架的尺寸爲640x480,那麼我添加的子圖層只能在繪製的1024x768 BufferedImage的640x480分數內繪製。 我想在某些地方子組件使用JFrame父母的getPreferredSize,因爲孩子總是有這個值作爲邊界。所以最終我的縮放策略與孩子的繪畫行爲相沖突,因爲他們完全忽略了他們爲繪製而交付的圖形對象的邊界。

最終,曾經我做什麼,我的孩子層(從JPanel的衍生,如果該事項)當目標尺寸比我的「虛擬」屏幕尺寸更小的會被截斷。

任何人都可以提供更好的解決方案或提示我如何繞過圖形界限被忽略的奇怪行爲?

編輯:工作測試代碼

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.awt.event.MouseMotionListener; 
import java.awt.event.MouseWheelEvent; 
import java.awt.event.MouseWheelListener; 
import java.awt.geom.AffineTransform; 
import java.awt.image.BufferedImage; 
import javax.print.attribute.standard.OrientationRequested; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

public class AffineTransformTest 
{ 

private static TransformingFrame canvas; 
private static JButton button; 
private static TestLayer layer; 

public static void main(String[] args) 
{ 
    canvas = new TransformingFrame(); 
    canvas.addMouseWheelListener(new ScaleHandler()); 

    layer=new TestLayer(canvas.originalSize); 
    canvas.getContentPane().add(layer); 
    layer.setVisible(true); 
    button = new JButton("asdf"); 
    canvas.setUndecorated(true); 
    button.setVisible(true); 
    canvas.getContentPane().add(button); 


    canvas.pack(); 



    canvas.setLayout(new BorderLayout()); 
    canvas.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
    canvas.setPreferredSize(canvas.originalSize); 
    canvas.setSize(canvas.originalSize); 
    canvas.setLayout(null); 

    canvas.setVisible(true); 
    canvas.validate(); 
} 

@SuppressWarnings("serial") 
private static class TransformingFrame extends JFrame 
{ 
    private double scale; 
    private final Dimension originalSize; 
    private AffineTransform tx = new AffineTransform(); 

    TransformingFrame() 
    { 
     originalSize=new Dimension(800,600); 
     scale = 1; 
    } 

    @Override 
    public void paint(Graphics g) 
    { 
     BufferedImage offscreenBuffer=new BufferedImage(originalSize.width,originalSize.height, BufferedImage.TYPE_INT_ARGB); 
     Graphics bufferGraphics=offscreenBuffer.getGraphics(); 
     super.paint(bufferGraphics); 
     bufferGraphics.dispose(); 

     ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB); 
     ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
     ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); 
     g.setColor(Color.black); 
     g.fillRect(0, 0, getWidth(), getHeight()); 
     ((Graphics2D) g).drawImage(offscreenBuffer, tx,null); 
    } 
    @Override 
    public void paintComponents(Graphics g) 
    { 
     BufferedImage offscreenBuffer=new BufferedImage(originalSize.width,originalSize.height, BufferedImage.TYPE_INT_ARGB); 
     Graphics bufferGraphics=offscreenBuffer.getGraphics(); 
     super.paintComponents(bufferGraphics); 
     bufferGraphics.dispose(); 

     ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB); 
     ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
     ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); 
     g.setColor(Color.black); 
     g.fillRect(0, 0, getWidth(), getHeight()); 
     ((Graphics2D) g).drawImage(offscreenBuffer, tx,null); 

    } 
    @Override 
    public void paintAll(Graphics g) 
    { 
     BufferedImage offscreenBuffer=new BufferedImage(originalSize.width,originalSize.height, BufferedImage.TYPE_INT_ARGB); 
     Graphics bufferGraphics=offscreenBuffer.getGraphics(); 
     super.paintAll(bufferGraphics); 
     bufferGraphics.dispose(); 

     ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB); 
     ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
     ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); 
     g.setColor(Color.black); 
     g.fillRect(0, 0, getWidth(), getHeight()); 
     ((Graphics2D) g).drawImage(offscreenBuffer, tx,null); 
} 

} 

@SuppressWarnings("serial") 
private static class TestLayer extends JPanel{ 

public TestLayer(Dimension originalSize) 
{ 
    this.setPreferredSize(originalSize); 
    this.setSize(originalSize); 
    setOpaque(false); 
    setDoubleBuffered(false); 
} 

@Override 
public void paint(Graphics g) 
{ 
    Graphics2D ourGraphics = (Graphics2D) g; 
    super.paint(ourGraphics); 
    ourGraphics.setColor(Color.green); 
    ourGraphics.fillRect(0, 0, getWidth(), getHeight()); 
    ourGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
    ourGraphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 
    ourGraphics.setColor(Color.BLACK); 

    ourGraphics.drawRect(50, 50, 50, 50); 
    ourGraphics.fillOval(100, 100, 100, 100); 
    ourGraphics.drawString("Test Affine Transform", 50, 30); 
    ourGraphics.drawString(canvas.tx.toString(), 50, 250); 
} 

} 

private static class ScaleHandler implements MouseWheelListener 
{ 
    public void mouseWheelMoved(MouseWheelEvent e) 
    { 
     if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) 
     { 

      // make it a reasonable amount of zoom 
      // .1 gives a nice slow transition 
      canvas.scale += (.1 * e.getWheelRotation()); 
      // don't cross negative threshold. 
      // also, setting scale to 0 has bad effects 
      canvas.scale = Math.max(0.00001, canvas.scale); 
      canvas.tx.setTransform(new AffineTransform()); 
      canvas.tx.scale(canvas.scale, canvas.scale); 
      canvas.setPreferredSize(new Dimension((int)(canvas.originalSize.width*canvas.scale),(int)(canvas.originalSize.height*canvas.scale))); 
      canvas.setSize(new Dimension((int)(canvas.originalSize.width*canvas.scale),(int)(canvas.originalSize.height*canvas.scale))); 
      canvas.validate(); 
      canvas.repaint(); 
     } 
    } 
} 

} 

由於某種原因該代碼工作:與未經換算的輸出,expectet輸出和產生的輸出

expected output resulted output

更新上述代碼更新結果(除了按鈕消失)..也許我的錯誤是在其他地方的兒童層..我會去調查,

好幾個小時與它周圍的擺弄之後,我得出的結論是,繪圖限制孩子小組在油漆(圖形G)方法獲得不允許畫比母體的規模。在這個例子中它可以工作,但在完整的應用程序中並不行似乎一些設置強制在我的應用程序上的行爲,但不是演示應用程序。

回答

2

所以,如果我的父框架具有尺寸640×480,我已經加入到它只能的1024×768

640x480的分數內畫創作JFrame子層 - >放在那裏JScrollPane - >到JScrollPane放:

1)JPanelJComponent與倍率paintComponentn(Graphics g)paint(Graphics g)

2)你寫BufferedImage,那麼更好的辦法是把BufferedImageIconJLabel

+0

我在代碼中沒有使用標籤,並且我也以同樣的方式覆蓋Paintcomponents和PaintAll,它的確有部分功能。唯一的問題是在縮放發生之前,我添加到JPanel中的部分圖層被切斷。 – anubisviech

+0

@anubisviech沒有開玩笑,真正的幫助你的問題,你必須編輯你的問題,並在這裏張貼代碼http://sscce.org/表格, – mKorbel

+0

謝謝你的提示,虐待嘗試明天張貼減少可編譯的樣本 – anubisviech

1

正如您所觀察到的,一個組件可以在縮放圖形上下文進行渲染,但結果是有效無用:UI委託具有沒有關於幾何變化的知識。正如@mKorbel所建議的,JScrollPane是傳統的選擇。

您也可以查看此game中使用的方案或此scalable label中使用的技術。如果您願意製作您自己的組件,則可以採用此ScaledView中顯示的方法。

+0

ScaledView可能是一個解決方案,因爲我不想縮放每一個圖層,而是想繪製整個場景,並在繪製所有內容時在最終傳遞中對其進行縮放。 – anubisviech

0

我的問題在詢問一些關於此問題的ppl後完全解決了。 的解決方案是: 1. 創建一個新的類,你可以借鑑,使操作出現,比如:以後

private class ScaledPane extends JPanel 
{ 
    public ScaledPane(Window parent) 
    { 
     super(); 
     setPreferredSize(new Dimension(parent.getDesiredWidth(), parent.getDesiredHeight())); 
     setSize(this.getPreferredSize()); 
    } 

    @Override 
    public void paint(Graphics g) 
    { 
     Graphics2D g2 = (Graphics2D) g.create(0, 0, getWidth(), getHeight()); 
     g2.setTransform(screenScale); 
     g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); // 
     System.out.println(g2.getClip()); 
     super.paint(g2); 
    } 
} 

這個類的一個實例設置爲您的contentPane:

setScreenScale(AffineTransform.getScaleInstance((double) width/(double) desiredWidth, (double) height/(double) desiredHeight)); 
    setContentPane(new ScaledPane(this)); 

做完之後,一切都很順利,因爲窗口的組件使用contentpanes繪製方法來繪製自己的新圖形對象,並在那裏設置了新的圖形對象

完成後,可以將我的窗口縮放到任何所需的大小,而無需操縱任何兒童的運動公式或位置。