2012-10-31 54 views
0

所以,我有一個菜單,工具欄和麪板的JFrame。我在面板中加載圖像,但出於某種奇怪的原因(至少對我而言),它們沒有正確顯示在面板中。有時他們在工具欄下面,有時在上面。此外,圖像在底部切割。該代碼是一個可以編譯和測試的完整代碼。提前致謝。面板內部的繪製圖像似乎有錯誤的x,y偏移

含有幀的類別:

import java.awt.BorderLayout; 
    import java.awt.Color; 
    import java.awt.Dimension; 
    import java.awt.FileDialog; 

    import java.awt.Toolkit; 
    import java.awt.event.ActionEvent; 
    import java.awt.event.ActionListener; 
    import java.awt.image.BufferedImage; 
    import java.io.BufferedInputStream; 
    import java.io.File; 
    import java.io.FileInputStream; 
    import java.io.IOException; 
    import java.util.zip.ZipInputStream; 

    import javax.imageio.ImageIO; 
    import javax.swing.BorderFactory; 
    import javax.swing.JButton; 
    import javax.swing.JFileChooser; 
    import javax.swing.JFrame; 
    import javax.swing.JMenu; 
    import javax.swing.JMenuBar; 
    import javax.swing.JMenuItem; 
    import javax.swing.JPanel; 
    import javax.swing.JToolBar; 
    import javax.swing.border.BevelBorder; 
    import javax.swing.border.Border; 
    public class SSCE extends JFrame { 
     private JComicPanel panel; 
     private JToolBar toolbar; 
     private JButton buttonZoom; 
     private JButton buttonPrev; 
     private JButton buttonNext; 
     private JMenuBar menuBar; 

     private Dimension dim; 
     private BufferedImage img; 
     private int currentPage; 
     private JFrame parentFrame; 




       public SSCE(){ 

        super("JComic"); 
        BorderLayout layout = new BorderLayout(); 
        setLayout(layout); 

        dim = Toolkit.getDefaultToolkit().getScreenSize(); 

        setSize((int)(dim.width /2.5),dim.height); 

        this.setPreferredSize(new Dimension((int) (dim.width /2.5),dim.height)); 

        createToolbar(); 
        createPanel(); 

        add(toolbar,BorderLayout.NORTH);  

        add(panel,BorderLayout.CENTER); 


        createMenu(); 
        add(menuBar); 
        setJMenuBar(menuBar); 
        panel.setVisible(true); 
        img = null; 
        pack(); 
        parentFrame = this; 

       } 


       private void createPanel(){ 
        Border raisedbevel, loweredbevel; 
        raisedbevel = BorderFactory.createRaisedBevelBorder(); 
        loweredbevel = BorderFactory.createLoweredBevelBorder(); 
        panel = new JComicPanel(img); 
        panel.setBorder(BorderFactory.createCompoundBorder(raisedbevel,loweredbevel)); 


       } 
       private void createToolbar(){ 
        toolbar = new JToolBar(); 
        toolbar.setPreferredSize(new Dimension(dim.width,45)); 
        toolbar.setFloatable(false); 
        buttonZoom = new JButton("+"); 

        toolbar.add(buttonZoom); 
        buttonPrev = new JButton("<-"); 
        toolbar.add(buttonPrev); 
        buttonNext = new JButton("->"); 
        toolbar.add(buttonNext); 
        toolbar.setBackground(Color.RED); 


       } 
       private void createMenu(){ 
        JMenu menuFile,menuJComic; 
        JMenuItem fileOpen; 
        JMenuItem quitJComic,aboutJComic; 


        menuBar = new JMenuBar(); 
        menuJComic = new JMenu("JComic"); 
        aboutJComic = new JMenuItem("About JComic..."); 
        menuJComic.add(aboutJComic); 
        quitJComic = new JMenuItem("Quit"); 
        quitJComic.addActionListener(
          new ActionListener(){ 
           public void actionPerformed(ActionEvent e) { 
            System.exit(0); 
           } 
          } 
          ); 
        menuJComic.add(quitJComic); 

        menuBar.add(menuJComic); 

        menuFile = new JMenu("File"); 

        fileOpen = new JMenuItem("Open..."); 
        fileOpen.addActionListener(
          new ActionListener(){ 
           public void actionPerformed(ActionEvent e) { 
            try { 


             img = ImageIO.read(new File("superman.jpg")); 
             currentPage = 1; 

             int offset = menuBar.getHeight() + toolbar.getHeight(); 
             panel.setImage(img,parentFrame,offset); 


            } 
            catch (IOException e1) { 
             System.out.println(e1.getMessage()); 
            } 

           } 
          } 
          ); 

        menuFile.add(fileOpen); 
        menuBar.add(menuFile); 


       } 

     /** 
     * @param args 
     */ 
     @SuppressWarnings("deprecation") 
     public static void main(String[] args) { 
      // TODO Auto-generated method stub 
      SSCE f = new SSCE(); 
      f.show(); 

     } 

    } 

類面板的

import java.awt.Color; 
    import java.awt.Dimension; 
    import java.awt.Graphics; 
    import java.awt.Graphics2D; 
    import java.awt.Image; 
    import java.awt.RenderingHints; 
    import java.awt.event.ComponentAdapter; 
    import java.awt.event.ComponentEvent; 
    import java.awt.image.BufferedImage; 
    import java.io.File; 

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

    public class JComicPanel extends JPanel{ 
     private BufferedImage img; 
     private int offset; 
     private final float scaling = 0.5f; 
     public JComicPanel(BufferedImage img){ 
      super(); 
      this.img = img; 
      addComponentListener(new ComponentAdapter() { 
       @Override 
       public void componentResized(ComponentEvent e) 
       { 
        repaint(); 
       } 
      }); 

     } 




     public void setImage(BufferedImage img,JFrame parentFrame,int offset){ 



      try{ 

       int w = img.getWidth(); 
       int h = img.getHeight(); 
       int newW = (int)(w * scaling); 
       int newH = (int)(h * scaling); 
       BufferedImage dimg = new BufferedImage(newW, newH, img.getType()); 
       Graphics2D g = dimg.createGraphics(); 
       g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 
       g.drawImage(img, 0, 0, newW, newH, 0, 0, w, h, null); 
       this.img = img; 
       System.out.printf("dim %d x %d",newW,newH); 


       this.setSize(new Dimension(newW,newH+offset)); 

       parentFrame.pack(); 
      } 
      catch(Exception e){ 
      } 


     } 

     public Dimension getPreferredSize(){ 

      return new Dimension(img.getWidth(),img.getHeight()); 
     } 

     public void paintComponent(Graphics g){ 

       // Draw our Image object. 
       super.paintComponent(g); 
       g.drawImage(img,0,0,getSize().width,getSize().height, this); // at location 50,10 
       System.out.println("painting 2"); 
       } 

    } 

圖片superman.jpg可以在這裏http://i50.tinypic.com/2yxnc3n.jpg找到。正如你所看到的圖像在工具欄下面,但在我的完整代碼中它也在上面。

+0

問題是什麼可見的? –

+0

Ehm,問題是,「爲什麼圖像在工具欄下方或上方移動?」?不應該從JPanel的(0,0)開始繪製嗎? – tagomago

+2

不要在任何地方設置大小。相反,給你的繪圖JPanel一個'getPreferredSize()'覆蓋,如果它保存一個圖像,讓它返回該圖像的尺寸。然後考慮在圖像更改後在頂層窗口調用'pack()'。此外,你幾乎從不應該有一個空的catch塊。另外,當你完成繪圖時,不要忘記處理你的BufferedImage的Graphics上下文。 –

回答

5

讓我們從這裏開始......

public void setImage(BufferedImage img,JFrame parentFrame,int offset){ 
    try{ 
     // You're scaling the incoming image, which means you no longer 
     // have a reference to the original image should you want to 
     // change that scale... 
     // You're previous code... 

     // Don't do this. The parent container's layout manager will simple 
     // override it, so it's useless... 
     this.setSize(newW,newH); 
     repaint(); 

     // This is a bad idea (personally)... 
     parentFrame.setSize(newW,newH+offset); 
    } catch(Exception e){ 
    } 
} 

調用這樣setSize將暫時允許組件假設你已經設定的尺寸。如果您之後要撥打invalidate(),則組件實際上會重新調整大小以符合佈局管理器的要求。

更大的問題是,您正在設置父框架的大小,但您不知道框架的佈局要求與其他組件有關,例如工具欄,菜單欄和框架(例如)

這沒有考慮被繪製圖像與原始圖像

g.drawImage(img,0,0,getSize().width,getSize().height, this); 

的比率作爲它已經被建議,縮放後的圖像,這可能是更容易簡單地設置圖像作爲的圖標JLabel已被添加到圖像窗格使用BorderLayout

你假定面板的大小是正確的,但它不會像面板的佈局管理器接管。

這是多餘的,因爲Swing會在調整大小時自動重新繪製組件。

addComponentListener(new ComponentAdapter() { 
    @Override 
    public void componentResized(ComponentEvent e) 
    { 
     repaint(); 
    } 
}); 

你最好的選擇是要麼刪除圖像窗格成滾動窗格,或重新調整圖像以動態貼合窗格的大小。

例如...

可擴展頁

enter image description hereenter image description here

public class ComicPage { 

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

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

       try { 
        BufferedImage page = ImageIO.read(getClass().getResource("/1346.gif")); 
        ComicPagePane comicPagePane = new ComicPagePane(); 
        comicPagePane.setComicPage(page); 

        JFrame frame = new JFrame(); 
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        frame.setLayout(new BorderLayout()); 
        frame.add(comicPagePane); 
        frame.setSize(200, 200); 
        frame.setLocationRelativeTo(null); 
        frame.setVisible(true); 
       } catch (Exception exp) { 
        exp.printStackTrace(); 
       } 
      } 
     }); 
    } 

    public class ComicPagePane extends JPanel { 

     private BufferedImage comicPage; 
     private Image scaledInstance; 

     public void setComicPage(BufferedImage page) { 
      if (page != comicPage) { 
       comicPage = page; 
       scaledInstance = null; 
       repaint(); 
      } 
     } 

     @Override 
     public void invalidate() { 
      scaledInstance = null; 
      super.invalidate(); 
     } 

     public BufferedImage getComicPage() { 
      return comicPage; 
     } 

     public double getScaleFactor(int iMasterSize, int iTargetSize) { 
      return (double) iTargetSize/(double) iMasterSize; 
     } 

     public double getScaleFactorToFit(BufferedImage img) { 
      double dScale = 1d; 

      double dScaleWidth = getScaleFactor(img.getWidth(), getWidth()); 
      double dScaleHeight = getScaleFactor(img.getHeight(), getHeight()); 

      dScale = Math.min(dScaleHeight, dScaleWidth); 

      return dScale; 
     } 

     protected Image getScaledInstance(BufferedImage master) { 
      if (scaledInstance == null) { 
       double scaleFactor = getScaleFactorToFit(master); 
       System.out.println("scaleFactor = " + NumberFormat.getNumberInstance().format(scaleFactor)); 

       // This is not the best scaling alorithm 
       scaledInstance = master.getScaledInstance(
         (int) Math.round(master.getWidth() * scaleFactor), 
         (int) Math.round(master.getHeight() * scaleFactor), Image.SCALE_SMOOTH); 
      } 
      return scaledInstance; 
     } 

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

      BufferedImage comicPage = getComicPage(); 
      if (comicPage != null) { 
       Graphics2D g2d = (Graphics2D) g.create(); 

       int width = getWidth(); 
       int height = getHeight(); 

       // Normally, I would put this into a background worker as this 
       // operation can be expensive.... 
       Image scaledInstance = getScaledInstance(comicPage); 

       int x = (width - scaledInstance.getWidth(this))/2; 
       int y = (height - scaledInstance.getHeight(this))/2; 
       g2d.drawImage(scaledInstance, x, y, this); 
       g2d.dispose(); 
      } 
     } 
    } 
} 

滾動頁面

enter image description here

public class ScrollableComicPage { 

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

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

       try { 
        BufferedImage page = ImageIO.read(getClass().getResource("/1346.gif")); 
        ComicPagePage comicPagePane = new ComicPagePage(); 
        comicPagePane.setComicPage(page); 

        JFrame frame = new JFrame(); 
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
        frame.setLayout(new BorderLayout()); 
        frame.add(new JScrollPane(comicPagePane)); 
        frame.pack(); 
        frame.setLocationRelativeTo(null); 
        frame.setVisible(true); 
       } catch (Exception exp) { 
        exp.printStackTrace(); 
       } 
      } 
     }); 
    } 

    public class ComicPagePage extends JPanel { 

     private BufferedImage comicPage; 

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

     public void setComicPage(BufferedImage page) { 
      if (page != comicPage) { 

       comicPage = page; 
       invalidate(); 
       repaint(); 
      } 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      if (comicPage != null) { 
       Graphics2D g2d = (Graphics2D) g.create(); 
       g2d.drawImage(comicPage, 0, 0, this); 
       g2d.dispose(); 
      } 
     } 
    } 
} 

有關縮放技術的更多信息,您可以通過Java: maintaining aspect ratio of JPanel background image進行閱讀。

+0

感謝您的代碼和輸入。現在我會嘗試修復我的。仍然無法理解爲什麼setSize導致圖像出現並將其刪除。爲什麼重漆不會產生任何結果? – tagomago

+0

'repaint'是重繪管理員在將來某個時間執行繪畫的請求。沒有保證油漆何時會發生或是否會發生。在這種情況下,調用'invalidate'和'repaint'可能會解決問題,因爲重繪管理器會考慮組件層次結構的狀態。重繪是非常聰明的,並且試圖減少它爲提高應用程序性能所做的塗料的數量,有時候這對於智能來說有點小巧。看看[在AWT和Swing中繪製](http://www.oracle.com/technetwork/java/painting-140037.html) – MadProgrammer

+2

+1代碼,但看着*「讓我們從這裏開始.. 。「*代碼讓我覺得這個GUI更適合在'JLabel'中顯示圖像。 –

2

的技術原因是你暫時將菜單欄到contentPane的中心,這是相同的邏輯位置作爲先前添加的面板:

add(panel, BorderLayout.CENTER); 
// following line is wrong - must be removed!!! 
add(menuBar); // no constraint == BorderLayout.CENTER 
setJMenuBar(menuBar); 

這樣做推動面板出關控制的佈局管理器,但沒有超出面板 - 最終結果是它沒有限制。 (這需要添加到rootPane的layeredPane中,而不是contentPane - 這就是爲什麼它有自己的專用方法setJMenuBar),同樣的混亂會發生在任何其他任意組件中心。

除此之外,我建議你清理你的代碼:

  • 刪除所有 setXXSize(some reasons
  • 決定幀是否應該拿出其首選(使用包)或任意固定大小(使用setSize)。前者是正確的啄在大多數情況下做的,後者有其使用情況 - 但是這樣既沒有意義
  • 組件默認
+0

是的,改變了順序,並設置了工具欄的首選尺寸,現在它似乎工作。謝謝。 – tagomago

+0

** DO.NOT.SETPREFERRED.SIZE.EVER **否,順序與此無關。 .. – kleopatra

相關問題