【问题标题】:paintComponent not called when calling JScrollPane调用 JScrollPane 时未调用paintComponent
【发布时间】:2013-11-20 17:23:41
【问题描述】:

我正在尝试使用 JFileChooser 加载背景图像,但是当操作结束时,paintcomponent() 方法没有按预期调用。 [编辑] 出于这个原因,我没有在背景图像上放一个红球,而是只有一个红球。

我在其他几个主题中读到应该将我的 Mappa 对象的实例添加到框架中: Why is paint()/paintComponent() never called? paintComponent not being called at the right time PaintComponent is not being called

但这并不能解决我的问题:我创建了一个 JScrollPane,它在构造函数中获取我的组件并将 JScrollPane 链接并使用

将其添加到主框架中

frmEditor.getContentPane().add(scrollabile, BorderLayout.CENTER);

这是主 Gui 的代码

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.ImageIcon;
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.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.UIManager;

public class Gui implements ActionListener {

    private JFrame frmEditor;

    Mappa content;
    private JMenuItem mntmSfondo;
    private JScrollPane scrollabile;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    Gui window = new Gui();
                    window.frmEditor.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public Gui() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frmEditor = new JFrame();
        frmEditor.setFont(UIManager.getFont("TextArea.font"));
        frmEditor.setBounds(50, 50, 1024, 768);
        frmEditor.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmEditor.getContentPane().setLayout(new BorderLayout(0, 0));

        JPanel panelTile = new JPanel();
        panelTile.setLayout(new BorderLayout(0, 0));

        JPanel panelStrum = new JPanel();

        panelStrum.setLayout(new GridLayout(15, 2));

        content = new Mappa(null);
        content.setMinimumSize(new Dimension(150, 150));
        scrollabile = new JScrollPane(content);
        scrollabile
                .setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        scrollabile
                .setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
        frmEditor.getContentPane().add(scrollabile, BorderLayout.CENTER);

        inizializzaMenu();
    }

    /**
     * Initialize the menu.
     */
    private void inizializzaMenu() {

        JMenuBar menuBar = new JMenuBar();
        frmEditor.setJMenuBar(menuBar);
        JMenu mnFile = new JMenu("File");
        mnFile.setFont(UIManager.getFont("TextArea.font"));

        JMenu mnAltro = new JMenu("Modify");
        mnAltro.setFont(UIManager.getFont("TextArea.font"));
        menuBar.add(mnAltro);

        mntmSfondo = new JMenuItem("Load Background");
        mntmSfondo
                .setIcon(new ImageIcon(
                        Gui.class
                                .getResource("/com/sun/java/swing/plaf/windows/icons/TreeOpen.gif")));
        mntmSfondo.setFont(UIManager.getFont("TextArea.font"));
        mntmSfondo.addActionListener(this);
        mnAltro.add(mntmSfondo);
    }

    public void actionPerformed(ActionEvent e) {
        Object source = e.getSource();
        if (source == mntmSfondo) {
            JFileChooser fc = new JFileChooser("tuttiSfondi");
            int result = fc.showOpenDialog(null);
            if (result == JFileChooser.APPROVE_OPTION) {
                File file = fc.getSelectedFile();
                try {
                    content = new Mappa(file);
                } catch (Exception ex) {
                }
            }
            if (result == JFileChooser.CANCEL_OPTION) {
            }
        }
    }

}

虽然这是 Mappa 类的代码,但我想用它来从 JFileChooser 加载背景。

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;

import javax.imageio.ImageIO;
import javax.swing.*;

public class Mappa extends JPanel {

    Image immagine;

    public Mappa(File fileImmagine) {

        if (fileImmagine != null ) {
            BufferedImage img = null;
            try {
                img = ImageIO.read(new File(fileImmagine.getPath()));
            } catch (IOException e) {
                e.printStackTrace();
            }
            this.immagine = img;
        }
        repaint();
    }

    public void paintComponent(Graphics g) {

        super.paintComponent(g);
        g.clearRect(0, 0, 4000, 4000);
        g.drawImage(immagine, 0, 0, null);

        g.setColor(Color.red);
        g.fillOval(170, 170, 150, 150);

        System.out.println("Called Repaint() on Mappa");

    }


}

问题不在于图像路径不正确,因为如果我“手动”在 Mappa 类上设置路径,通过提供路径而不是在 ImageIO.read 中使用 new File(fileImmagine.getPath()),它会加载,但是调用了该 paintComponent只有一次,当从 Gui 类调用 Mappa 的构造函数时

【问题讨论】:

    标签: java swing jscrollpane paintcomponent jfilechooser


    【解决方案1】:

    当您设置背景时,您只分配新的Mappa 实例,而不是实际将其添加到任何容器中。尝试添加以下内容:

    scrollabile.setViewportView(content);
    

    或者,替换 Mappa 类中的图像。即:

    public void setImage(File file) throws IOException {
        this.immagine = ImageIO.read(file);
        repaint();
    }
    

    另外,在paintComponent() 中,您可以使用面板尺寸来填充整个区域:

    g.drawImage(immagine, 0, 0, getWidth(), getHeight(), this);
    

    并且不要忘记使用有效的ImageObserver,因为JPanel 实现了一个。

    【讨论】:

    • 我尝试在frmEditor.getContentPane().add(scrollabile, BorderLayout.CENTER); 之后和之前添加scrollable.setViewportView(content);,但没有成功。 Vandale 提出的在 Mappa 类上添加 setImage 函数的建议实际上解决了问题,谢谢!!
    • @Kaeel,我们的想法是在重新分配Mappa 后立即在actionPerformed() 中调用scrollabile.setViewportView(content);。但替换现有Mappa 中的图像更简单。
    • 我刚试过;它也确实有效,我还学到了一个新东西。很抱歉,我仍然没有足够的声望来支持你们两个,当我的声望达到 15 时,我会回来回答这个问题!
    • @Kaeel 很高兴它成功了! :) 考虑改用setImage() 方法,因为重新分配和更换组件的成本更高。
    【解决方案2】:

    您实际上并未修改已添加到框架中的Mapa 实例。线

    content = new Mappa(file);
    

    actionPerformed() 中不会更改框架中的面板,它只会重新分配局部变量。相反,您应该在Mapa 中放置一个诸如updateImage() 之类的方法,该方法将更新Mapa 显示的图像。您还需要在此之后调用repaint(),以便它重新绘制新图像。

    【讨论】:

    • 谢谢,看来这是代码的实际问题。我在 Mappa 类中创建了一个 updateImage 方法,并使用类似 content.setImage(file); 的方式从 GUI 调用它
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多