面板内的绘制图像似乎有错误的x,y偏移

时间:2012-10-31 19:49:15

标签: java swing jmenubar

所以,我有一个带有菜单,工具栏和面板的JFrame。我在面板内加载图像,但由于一些奇怪的原因(至少对我来说),它们没有在面板中正确显示。有时它们从工具栏开始,有时在上面。此外,图像在底部切割。代码是完整的代码,可以编译和测试。提前致谢。

包含框架的类:

    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找到。正如您所看到的,图像位于工具栏下方,但在我的完整代码中,它也在上面。

2 个答案:

答案 0 :(得分: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(),则实际上会重新调整组件的大小以满足布局管理器的要求。

更大的问题是您正在设置父框架的大小,但您不知道框架的布局要求与其他组件有关,例如工具栏,菜单栏和框架(例如)< / p>

这是在不考虑原始图像的比率的情况下绘制图像

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 here enter 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,了解有关缩放技术的更多信息。

答案 1 :(得分:2)

技术原因是您暂时将menuBar添加到contentPane的中心,即与之前添加的面板相同的逻辑位置:

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

这样做会将面板推出LayoutManager的控制范围,但不会超出面板 - 净效果是它没有约束。

这并不是特别的是菜单栏(这需要被添加到为rootPane的layeredPane,不contentPane中 - 这就是为什么它有自己专门的方法setJMenuBar),同样的混乱将与在其他任意成分发生中心。

除此之外,我建议你清理你的代码:

  • 删除所有 setXXSize(some reasons
  • 决定框架是否应该以其首选(使用包)或任意固定大小(使用setSize)出现。在大多数情况下,前者是正确的事情,后者有其用例 - 但两者都没有意义
  • 默认情况下可以看到组件