java - 在已经可见的框架上调用 setVisible(true)

标签 java swing jpanel awt repaint

问题:

在已经可见的 JFrame 上调用 setVisible(true) 有什么作用?我正在挖掘 JFrame 的源代码,最终归结为 this function in Component如果它已经可见,它对框架没有任何作用。为什么它的行为像 revalidate();重绘();? (见下文 SSCCE)


动机:

我正在开发一个 java 应用程序,为此我编写了一个类 JImagePanel,它扩展了 JPanel 并允许用户将图像设置为背景(请参阅 SSCCE) .我发现在编辑面板的背景后,我无法将背景重新绘制为正确的大小。在网上搜索后,我发现以下工作:

if(frame.isVisible()) frame.setVisible(true);

最终,我使用

解决了这个问题
panel.revalidate();
panel.repaint();

,我认为这是更好的解决方案,但它让我开始思考 setVisible(true) 在已经可见的框架上实际上做了什么。在我看来,它不应该起作用 - 但实际上它起作用了。


中南合作商会

这是一个说明我的问题的例子。如果不出意外,希望您将来会发现这门课非常有用。

注意:此文件的更新源可以在项目主页上找到 GitHub这是为该项目创建的。

尽情享受吧!

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(),这依次重新验证框架中的所有子组件。

具体原因,引用Component.setVisible(boolean b)的实现:

public void setVisible(boolean b) {
    show(b);
}

public void show(boolean b) {
    if (b) {
        show();
    } else {
        hide();
    }
}

但是 show() 方法在 Window 中被覆盖了(JFrame 是它的子类)。所以这最终调用了 Window.show():

public void show() {
    if (peer == null) {
        addNotify();
    }
    validate();
    [...]

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

关于java - 在已经可见的框架上调用 setVisible(true),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21137700/

相关文章:

java - Java 中参数数量可变的构造函数

java - 将可绘制对象从另一个 Activity 布局应用到 ImageView

java - 更改 JTextArea 中的位置标记颜色

java - ScrollBar 和 JTable 选择的问题

java - JPA 和序列化行为

java - 计时器无法正确触发

java - JOptionPane 获取密码

java 使用 JPanel 的大小来调整组件的大小

java - 做简单行走动画的好方法?

java - 如果 ArrayList 的 clone() 被破坏了,为什么他们不能修复它呢?