Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在已经可见的帧上调用setVisible(true)_Java_Swing_Jpanel_Awt_Repaint - Fatal编程技术网

Java 在已经可见的帧上调用setVisible(true)

Java 在已经可见的帧上调用setVisible(true),java,swing,jpanel,awt,repaint,Java,Swing,Jpanel,Awt,Repaint,问题: 在已经可见的JFrame上调用setVisible(true)做什么?我一直在挖掘的源代码,最终,它归结为,如果框架已经可见,它对框架没有任何影响。为什么它的行为像revalidate();重新油漆()?(见下文SSCCE) 动机: 我正在开发一个java应用程序,为此我编写了一个类JImagePanel,它扩展了JPanel,允许用户将图像设置为背景(请参见SSCCE)。我发现在编辑面板的背景后,我在将背景重新绘制到正确的大小时遇到了问题。在浏览互联网后,我发现以下几点很有效: if

问题:

在已经可见的JFrame上调用setVisible(true)做什么?我一直在挖掘的源代码,最终,它归结为,如果框架已经可见,它对框架没有任何影响。为什么它的行为像
revalidate();重新油漆()?(见下文SSCCE)


动机:

我正在开发一个java应用程序,为此我编写了一个类
JImagePanel
,它扩展了
JPanel
,允许用户将图像设置为背景(请参见SSCCE)。我发现在编辑面板的背景后,我在将背景重新绘制到正确的大小时遇到了问题。在浏览互联网后,我发现以下几点很有效:

if(frame.isVisible()) frame.setVisible(true);
最终,我使用

panel.revalidate();
panel.repaint();
,我认为这是更好的解决方案,但它让我思考
setVisible(true)
在已经可见的帧上实际做了什么。在我看来,它不应该起作用,但事实上它确实起作用了


SSCCE

这里有一个例子说明了我的问题。如果没有其他内容,希望您在将来发现这个类非常有用

注意:此文件的更新源可在创建此文件的项目的主页上找到

享受吧

package com.dberm22.utils;

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.Toolkit;
import java.awt.image.BufferedImage;

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

public class JImagePanel extends JPanel {

    private static final long serialVersionUID = 6841876236948317038L;
    private Image img = null;
    private Position position = Position.CENTER;

  public enum Position{
      STRETCH,
      CENTER,
      FIT,
      FILL,
      NONE;
  }

  public JImagePanel() {
      }

  public JImagePanel(String img) {
    this(new ImageIcon(img).getImage());
  }

  public JImagePanel(Image img) {

      setBackgroundImage(img);
  }

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

    Graphics2D g2 = (Graphics2D) g;

    g2.setColor(getBackground());
    g2.fillRect(0, 0, getWidth(), getHeight());

    if (this.position.equals(Position.STRETCH))
    { 
        if(this.img != null) g2.drawImage(img, 0, 0, getWidth(), getHeight(), null); 
    }
    else if (this.position.equals(Position.FILL) || this.position.equals(Position.FIT))
    { 
        if(this.img != null)
        {

             double scaleFactor = getScaleFactor(new Dimension(img.getWidth(null), img.getHeight(null)), getSize());
             int scaleWidth = (int) Math.round(img.getWidth(null) * scaleFactor);
             int scaleHeight = (int) Math.round(img.getHeight(null) * scaleFactor);

             //Image img_scaled = img.getScaledInstance(scaleWidth, scaleHeight, Image.SCALE_SMOOTH);
            g2.drawImage(scaleImage(img, scaleWidth, scaleHeight, getBackground()), (getWidth() - scaleWidth)/2, (getHeight() - scaleHeight)/2, scaleWidth, scaleHeight, null); 
        }
    }
    else if (this.position.equals(Position.CENTER)) { if(this.img != null) g2.drawImage(img, (getWidth() - img.getWidth(null))/2, (getHeight() - img.getHeight(null))/2, null); }
  }

  public void setBackgroundImage(String img) 
  {
      setBackgroundImage(new ImageIcon(img).getImage());
  }

  public void setBackgroundImage(Image img)
  {
        this.img = img;
        Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
        setPreferredSize(size);
        setMinimumSize(size);
        setMaximumSize(size);
        setSize(size);

        repaint();
  }

  public static double getScaleFactor(int iMasterSize, int iTargetSize) {

        double dScale = 1;
        if (iMasterSize > iTargetSize) {

            dScale = (double) iTargetSize / (double) iMasterSize;

        } else {

            dScale = (double) iTargetSize / (double) iMasterSize;

        }

        return dScale;

    }

    public double getScaleFactor(Dimension original, Dimension targetSize) {

        double dScale = 1d;

        if (original != null && targetSize != null) {

            double dScaleWidth = getScaleFactor(original.width, targetSize.width);
            double dScaleHeight = getScaleFactor(original.height, targetSize.height);

            if (this.position.equals(Position.FIT)) dScale = Math.min(dScaleHeight, dScaleWidth);
            else if(this.position.equals(Position.FILL)) dScale = Math.max(dScaleHeight, dScaleWidth);

        }

        return dScale;

    }

    public BufferedImage scaleImage(Image img, int width, int height, Color background) {

        BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = newImage.createGraphics();
        try {
            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                    RenderingHints.VALUE_INTERPOLATION_BICUBIC);
            g.setBackground(background);
            g.clearRect(0, 0, width, height);
            g.drawImage(img, 0, 0, width, height, null);
        } finally {
            g.dispose();
        }
        return newImage;
    }

  public void setBackgroundImagePosition(String pos)
  {
      if("Stretch".equals(pos)) setBackgroundImagePosition(Position.STRETCH);
      else if("Center".equals(pos))  setBackgroundImagePosition(Position.CENTER);
      else if("Fit".equals(pos)) setBackgroundImagePosition(Position.FIT);
      else if("Fill".equals(pos))  setBackgroundImagePosition(Position.FILL);
      else if("None".equals(pos)) setBackgroundImagePosition(Position.NONE);
  }
  public void setBackgroundImagePosition(Position pos)
  {
      this.position = pos;
      repaint();
  }

  public static void main(String[] args)
  {

      JFrame frame = new JFrame("JImagePanel Test");
      frame.setSize( Toolkit.getDefaultToolkit().getScreenSize());
      frame.setPreferredSize( Toolkit.getDefaultToolkit().getScreenSize());
      frame.setExtendedState(JFrame.MAXIMIZED_BOTH); //sets appropriate size for frame

      JImagePanel panel = new JImagePanel();
      frame.add(panel);

      frame.setVisible(true);

      try {Thread.sleep(2000);} catch (InterruptedException e) {}

      panel.setBackgroundImage("C:\\Users\\David\\Pictures\\Wood.jpg");
      panel.setBackgroundImagePosition(JImagePanel.Position.STRETCH);

      panel.revalidate(); // need to revalidate()
      panel.repaint(); //doesnt work by itself

      try {Thread.sleep(2000);} catch (InterruptedException e) {}

      panel.setBackgroundImage("C:\\Users\\David\\Pictures\\Wood.jpg");
      panel.setBackgroundImagePosition(JImagePanel.Position.FIT);

      frame.setVisible(true); //also works --why?

  }

}
在已可见的
JFrame
上调用
setVisible(true)
对您有效,因为这最终会在内部调用
validate()
,从而重新验证框架中的所有子组件

要了解原因,请参阅组件.setVisible(布尔b)
的实现:

但是
show()
方法在
Window
中被重写(其中
JFrame
是一个子类)。因此,这将调用
Window.show()


希望这能解释您所看到的行为。

假设您正在对imagePanel进行一半的清理:

  • 让面板根据需要进行自己的重新验证/喷漆(vs应用程序代码)
  • ,从来没有,甚至在面板内部都没有
这就是更改设置程序并覆盖getXXSize。请注意,仅基于图像大小的大小提示并不是您在实际代码中想要做的事情,您可能还需要考虑super的提示(如果面板有子项,则f.i.)

使用它的应用程序代码现在只需调用setter,而无需其他操作:

    JFrame frame = new JFrame("JImagePanel Test");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    // frame.setLayout(new FlowLayout()); // just to see the effect of a pref-respecting layout
    final JImagePanel panel = new JImagePanel();
    frame.add(panel);

    final Image[] images = new Image[]{
            XTestUtils.loadDefaultImage(), XTestUtils.loadDefaultImage("500by500.png"), null};
    Action toggleImage = new AbstractAction("toggle image") {
        int index = 0;
        @Override
        public void actionPerformed(ActionEvent e) {
            panel.setBackgroundImage(images[index]);
            index = (index +1) % images.length;
        }
    };
    Action togglePosition = new AbstractAction("toggle position") {
        int index = 0;
        @Override
        public void actionPerformed(ActionEvent e) {
            panel.setBackgroundImagePosition(Position.values()[index]);
            index = (index +1) % Position.values().length;
        }
    };
    frame.add(new JButton(toggleImage), BorderLayout.NORTH);
    frame.add(new JButton(togglePosition), BorderLayout.SOUTH);
    // size for frame
    //frame.setSize(800, 800);
    frame.setExtendedState(JFrame.MAXIMIZED_BOTH); //sets appropriate
    frame.setVisible(true);

为什么需要重新粉刷面板?您是否添加了一个新组件,或者有其他原因?发布a会有很大帮助。我确信从JFrame中重新验证()和重新绘制(),以刷新所有JComponents树,确保有一个潜在的问题repaint()可以关闭,对于JComponents这正是史前的AWT问题,如果不是基于AWT容器,请确保检查第三方代码,然后,您必须根据您的措辞重新绘制此容器(例如,reDraw()必须以良好的代码实现)。在添加面板之前,听起来您正在调用
revalidate()
。这是要验证的面板布局,因此应调用
revalidate();重新油漆()在删除和添加组件完成后。发布指向项目的链接不推荐,我们太懒了,无法浏览整个项目;-)相反,如前所述(尽管现在称为MCVE),将行为提取到SSCCE中。啊,窗口子类覆盖show()。我错过了-谢谢。这并不能回答问题(请参见Grodriguez),但在内部调用revalidate()无疑是对我的类的一种改进,我应该(也将)这样做。扩展测试用例为+1。谢谢你的意见。
public void show() {
    if (peer == null) {
        addNotify();
    }
    validate();
    [...]
@Override
public Dimension getPreferredSize() {
    if (img != null) {
        return new Dimension(img.getWidth(this), img.getHeight(this));
    }
    return super.getPreferredSize();
}

public void setBackgroundImage(Image img) {
    this.img = img;
    // need to revalidate as our sizing hints might have changed
    revalidate();
    repaint();
}

public void setBackgroundImagePosition(Position pos) {
    this.position = pos;
    repaint();
}
    JFrame frame = new JFrame("JImagePanel Test");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    // frame.setLayout(new FlowLayout()); // just to see the effect of a pref-respecting layout
    final JImagePanel panel = new JImagePanel();
    frame.add(panel);

    final Image[] images = new Image[]{
            XTestUtils.loadDefaultImage(), XTestUtils.loadDefaultImage("500by500.png"), null};
    Action toggleImage = new AbstractAction("toggle image") {
        int index = 0;
        @Override
        public void actionPerformed(ActionEvent e) {
            panel.setBackgroundImage(images[index]);
            index = (index +1) % images.length;
        }
    };
    Action togglePosition = new AbstractAction("toggle position") {
        int index = 0;
        @Override
        public void actionPerformed(ActionEvent e) {
            panel.setBackgroundImagePosition(Position.values()[index]);
            index = (index +1) % Position.values().length;
        }
    };
    frame.add(new JButton(toggleImage), BorderLayout.NORTH);
    frame.add(new JButton(togglePosition), BorderLayout.SOUTH);
    // size for frame
    //frame.setSize(800, 800);
    frame.setExtendedState(JFrame.MAXIMIZED_BOTH); //sets appropriate
    frame.setVisible(true);