【问题标题】:JPanel&JScrollPane and error renderingJPanel&JScrollPane 和错误渲染
【发布时间】:2012-03-18 20:49:57
【问题描述】:

我的英语不好,但我会尽力解释。 我有个问题。 在 JPanel 我画线....它们应该超出对象 JPanel 的区域,而 JScrollPane 理论上应该显示整个面板,但它没有更新,也没有显示为面板范围释放的所有行.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.Console;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class TestFrame extends JFrame {

    static int speed = 10;
    static int floor = 22;
    public static void createGUI() {
        JFrame frame = new JFrame("Test frame");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        final Font font = new Font("Verdana", Font.PLAIN, 25);

        JPanel butPanel = new JPanel();     

        JButton biginButton = new JButton("start");
        biginButton.setFont(font);
        biginButton.setFocusable(false);
        butPanel.add(biginButton);

        JButton remButton = new JButton("repaint");
        remButton.setFont(font);
        remButton.setFocusable(false);
        butPanel.add(remButton);

        final JPanel labPanel = new JPanel();
        final JScrollPane scrollPane = new JScrollPane(labPanel);
        labPanel.setLayout(new BoxLayout(labPanel, BoxLayout.Y_AXIS));

        biginButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                //labPanel.getGraphics().drawString("Ololo", 50, 50);
                int floH = 100;
                for(int i = 0; i < floor; i++){
                    labPanel.getGraphics().drawLine(0, i*floH, 300, i*floH);
                    labPanel.getGraphics().setColor(Color.RED);
                    scrollPane.revalidate();    
                }
            }
        });

        remButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                    labPanel.repaint();
                    scrollPane.revalidate();                                
            }           
        });

        frame.getContentPane().setLayout(new BorderLayout());
        frame.getContentPane().add(butPanel, BorderLayout.NORTH);
        frame.getContentPane().add(scrollPane, BorderLayout.CENTER);

        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        frame.setPreferredSize(new Dimension(screenSize.width-10, screenSize.height-10));
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame.setDefaultLookAndFeelDecorated(true);
                createGUI();
            }
        });
    }
}

【问题讨论】:

  • 那么真正的问题是什么?
  • 如果面板对象超出,你需要做的事情是绘制增加滚动
  • public class TestFrame extends JFrame { 将其更改为 public class TestFrame { & 该类应该像现在一样工作(或差)。

标签: java swing awt jpanel jscrollpane


【解决方案1】:

我猜您正在尝试绘制 JPanel,然后期望 JPanel 应该变大以容纳您的绘图,这不仅对您不起作用,而且如果您调用,您会丢失绘图JPanel 上的 repaint()。

如果是,那么,

  • 仅仅因为您绘制超出了 JPanel 或其他 JComponent 的大小并不会自动使该组件变大,因为组件本身不知道您正在绘制超出其边界的“知识”。如果你想调整组件的大小,你必须自己做。
  • 最好让 JPanel 通过覆盖其getPreferredSize() 方法来设置自己的大小。这将防止其他代码将其大小重置为其他值。
  • 您不想通过调用getGraphics() 来获取组件的图形。如此获得的 Graphics 对象是短暂的,一旦下次调用paint(...) 或paintComponent() 时,绘制的任何内容都会消失。可以在 BufferedImage 上调用 getGraphics(),但不能在 Component 或 JComponent 上调用(除非您有充分的理由这样做并且知道如何防止 Graphics 对象变为 null)。
  • 覆盖 JPanel 或其他一些 JComponent 并绘制该组件的 paintComponent(...) 覆盖方法。如果您使用的是 BufferedImage,则在此 paintComponent 方法中绘制 BufferedImage。

例如:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;

import javax.swing.*;

@SuppressWarnings("serial")
public class TestDrawing extends JPanel {
   private static final int PREF_W = 800;
   private static final int PREF_H = 600;
   private DrawingPanel drawingPanel = new DrawingPanel();

   public TestDrawing() {
      JPanel northPanel = new JPanel();
      northPanel.add(new JButton(new AbstractAction("Draw Lines") {

         @Override
         public void actionPerformed(ActionEvent arg0) {
            drawingPanel.drawLines();
            drawingPanel.repaint();
         }
      }));

      setLayout(new BorderLayout());
      add(new JScrollPane(drawingPanel));
      add(northPanel, BorderLayout.PAGE_START);
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   private static void createAndShowGui() {
      TestDrawing mainPanel = new TestDrawing();

      JFrame frame = new JFrame("TestDrawing");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class DrawingPanel extends JPanel {
   private static final int BI_W = 500;
   private static final int FLOOR = 22;
   private static final int FLO_H = 100;
   private BufferedImage img = new BufferedImage(BI_W, FLO_H * FLOOR, BufferedImage.TYPE_INT_ARGB);

   public DrawingPanel() {

   }

   public void drawLines() {

      Graphics g = img.getGraphics();
      g.setColor(Color.black);
      for (int i = 0; i < FLOOR; i++) {
         g.drawLine(0, i * FLO_H, 300, i * FLO_H);
         g.setColor(Color.RED);
      }
      g.dispose();
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(BI_W, FLO_H * FLOOR);
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (img != null) {
         g.drawImage(img, 0, 0, this);
      }
   }
}

【讨论】:

  • 哦。这正是我所需要的。非常感谢。
【解决方案2】:

参考这一行:

labPanel.getGraphics().drawLine(0, i*floH, 300, i*floH);

使用图形绘制线条不会超出图形对象的边界。这意味着线条实际上并没有超出面板的大小。您需要在绘制线条之前调整面板的大小。看看这是否有效:

int newWidth = Math.max(labPane.getWidth(),300);
int newHeight = Math.max(labPane.getHeight(),i*floH);
labPane.setPreferredSize(newWidth,newHeight);

labPanel.getGraphics().drawLine(0, i*floH, 300, i*floH);

【讨论】:

  • 请不要鼓励使用在组件上调用getGraphics() 来获取用于绘图的Graphics 对象。这个对象是短暂的,一旦下次调用paint(...)paintComponent(),任何绘制的东西都会消失。可以在 BufferedImage 上调用 getGraphics(),但不能在 Component 或 JComponent 上调用(除非您有充分的理由这样做并且知道如何防止 Graphics 对象变为 null)。
  • 总的来说,这件作品的精髓——一部电梯。画线 - 地板。将在电梯本身旁边绘制(矩形)。所有这些都将在流上起作用,但我认为这就是绘制形状的东西以及如何制作正常方式的地方,如果面板上的地板不在一起。毕竟,当电梯移动并超出面板时,必须重新绘制它。或者也许他一搬到另一层就重新绘制更好?以及是否将图形工作转移到另一个类?
  • @sombik:任何静止的背景图像都应该绘制在 BufferedImage 上,然后显示在 JPanel 的 paintComponent 方法中。图像的运动部分可以直接用同样的方法绘制出来。
猜你喜欢
  • 2017-05-29
  • 2012-08-14
  • 2014-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-28
  • 1970-01-01
相关资源
最近更新 更多