提问者:小点点

重画后JComponents移动到原点()


类似于JButton在调用重新绘制后出现在错误的位置,但是对这个问题的回答只解决了他没有使用布局管理器的事实,而我使用的是布局管理器(很差),所以不幸的是,这并没有真正帮助。

要显示1920x1080栅格的预览(缩小到640x480以节省空间),请在更改每个正方形的高度、宽度和列数时进行拉伸和收缩。(首先指定网格中的总平方数,这样程序就可以推断出行数。)

    < li >一个顶级JFrame。 < li >包含两个jpanel:Grid和sidebar,使用BorderLayout将它们对齐到东西两侧。 < li>Sidebar是一个JPanel,包含Y轴对齐的BoxLayout中的所有JComponents。 < li>Grid扩展JComponent,使用Graphics.drawLine()绘制网格。 < li >侧栏中的每个组件在更改为更新网格时都会调用Grid.repaint()。

当前UI,两个主要的JPanel以红色显示。

每当我更改任何组件并因此调用 Grid.repaint():

  1. 网格未清除,导致出现多行;
  2. 所有侧边栏
  3. 组件都绘制在左上角,同时仍然在侧边栏上显示/运行;
  4. 出于某种原因,网格会调整自身大小以使其比正常宽度。

当前的用户界面,但无聊。

    < li >将repaint()区域更改为仅覆盖网格的矩形, < li >检查文档中有关这方面的任何内容, < li >谷歌, < li >我问你们。
import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class BuildGridGUI2
{
    static final int WIDTH_MIN = 100;
    static final int WIDTH_MAX = 2000;
    static final int WIDTH_INIT = 520;
    
    static final int HEIGHT_MIN = 100;
    static final int HEIGHT_MAX = 2000;
    static final int HEIGHT_INIT = 300;
    
    int widthOfFrames = 255;
    int heightOfFrames = 255;
    int numCols = 3;
    int numFrames = 1;
    
    
    private final JComponent makeUI()
    {
        JPanel p = new JPanel();
        
        
        p.setLayout(new BorderLayout());
        
        Grid g = new Grid();
        JComponent j = makeSideMenu(g);
        
        g.setBorder(BorderFactory.createCompoundBorder(
              BorderFactory.createLineBorder(Color.red),
              g.getBorder()));
        
        
        j.setBorder(BorderFactory.createCompoundBorder(
                  BorderFactory.createLineBorder(Color.red),
                  j.getBorder()));
        
        
        p.add(j, BorderLayout.EAST);
        p.add(g, BorderLayout.WEST);
        
        
        return p;
    }
    
    private final JComponent makeSideMenu(Grid grid)
    {
        JPanel p = new JPanel();
        
        JLabel numColsSelectorLabel = new JLabel("Frames Per Column");
        JSpinner numColsSelectorField = new JSpinner();
        
        JLabel widthLabel = new JLabel("Width per Frame (Pixels)");
        JSpinner widthSpinner = new JSpinner();
        JSlider widthSlider = new JSlider(WIDTH_MIN, WIDTH_MAX, WIDTH_INIT);
        
        JLabel heightLabel = new JLabel("Height per Frame (Pixels)");
        JSpinner heightSpinner = new JSpinner();
        JSlider heightSlider = new JSlider(BuildGridGUI2.HEIGHT_MIN, BuildGridGUI2.HEIGHT_MAX, BuildGridGUI2.HEIGHT_INIT);
        JButton confirmButton = new JButton("Confirm");
        
        
        
        numColsSelectorField.setEditor(new JSpinner.NumberEditor(numColsSelectorField));
        numColsSelectorField.setMaximumSize(numColsSelectorField.getPreferredSize());
        
        
        
        widthSlider.setMajorTickSpacing(300);
        widthSlider.setMinorTickSpacing(20);
        widthSlider.setPaintTicks(true);
        widthSlider.setPaintLabels(true);
        
        
        
        widthSpinner.setEditor(new JSpinner.NumberEditor(widthSpinner));
        widthSpinner.setPreferredSize(new Dimension(70, 30));
        widthSpinner.setMaximumSize(widthSpinner.getPreferredSize());
        
        
        
        
        heightSlider.setMajorTickSpacing(300);
        heightSlider.setMinorTickSpacing(20);
        heightSlider.setPaintTicks(true);
        heightSlider.setPaintLabels(true);
        
        
        
        heightSpinner.setEditor(new JSpinner.NumberEditor(heightSpinner));
        heightSpinner.setPreferredSize(new Dimension(70, 30));
        heightSpinner.setMaximumSize(heightSpinner.getPreferredSize());
        
        
        confirmButton.addActionListener(new ActionListener() {
            @Override public void actionPerformed(ActionEvent e)
            {
                widthOfFrames = 200;
                grid.refresh();
            }
        });
        
        
        p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
        p.setPreferredSize(new Dimension(300, 480));
        p.setSize(new Dimension(300, 480));
        
        numColsSelectorLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
        numColsSelectorField.setAlignmentX(Component.CENTER_ALIGNMENT);
        widthSlider.setAlignmentX(Component.CENTER_ALIGNMENT);
        heightSlider.setAlignmentX(Component.CENTER_ALIGNMENT);
        confirmButton.setAlignmentX(Component.CENTER_ALIGNMENT);
        widthLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
        heightLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
        widthSpinner.setAlignmentX(Component.CENTER_ALIGNMENT);
        heightSpinner.setAlignmentX(Component.CENTER_ALIGNMENT);
        
        
        p.add(Box.createRigidArea(new Dimension(300, 30)));
        p.add(numColsSelectorLabel);
        p.add(Box.createRigidArea(new Dimension(300, 5)));
        p.add(numColsSelectorField);
        p.add(Box.createRigidArea(new Dimension(300, 25)));
        p.add(widthLabel);
        p.add(Box.createRigidArea(new Dimension(300, 3)));
        p.add(widthSpinner);
        p.add(widthSlider);
        p.add(Box.createRigidArea(new Dimension(300, 25)));
        p.add(heightLabel);
        p.add(Box.createRigidArea(new Dimension(300, 3)));
        p.add(heightSpinner);
        p.add(heightSlider);
        p.add(Box.createRigidArea(new Dimension(300, 45)));
        p.add(confirmButton);
        
        
        return p;
    }
    
    
    private static void createAndShowGUI() {
        BuildGridGUI2 b = new BuildGridGUI2();
        JFrame mainFrame = new JFrame("Grid Builder");
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.setSize(940, 480);
        mainFrame.getContentPane().add(b.makeUI());
        mainFrame.setResizable(false);
        mainFrame.setVisible(true);
    }
    
    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable() {
            @Override public void run() {
                createAndShowGUI();
            }
        });
    }
    
    
    class Grid extends JComponent
    {
        static final int CANVAS_WIDTH = 640;
        static final int CANVAS_HEIGHT = 480;
        
        private final double conversionRatio = 4.0/9.0; // 1080p scaled down to 480p preview
        
        private int squareHeight, squareWidth, numColumns, numRows;
        
        
        public Grid()
        {
            setOpaque(true);
            setSize(CANVAS_WIDTH, CANVAS_HEIGHT); // trying to get the size to work properly.
            setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
        }
        
        @Override
        public Dimension getPreferredSize()
        {
            return new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT);
        }
        
        @Override
        public void paintComponent(Graphics g)
        {
            
            super.paintComponent(g);
            
            updateVars();
            
            int k;
            
            for (k = 0; k < numColumns; k++)
            {
                // @param: (x1, y1), (x2, y2)
                g.drawLine(k * squareWidth, 0, k * squareWidth, CANVAS_HEIGHT);
            }
            
            for (k = 0; k < numRows; k++)
            {
                g.drawLine(0, k * squareHeight, CANVAS_WIDTH, k * squareHeight);
            }
        }
        
        public void refresh()
        {
            // Attempting to set the repaint area to only the grid region
            // because CTRL+F is free and parameters are not
            repaint(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
        }
        
        public void updateVars()
        {
            this.squareWidth = (int)(
                    (double)BuildGridGUI2.this.widthOfFrames
                    *
                    conversionRatio);
            
            this.squareHeight = (int)(
                    (double)BuildGridGUI2.this.heightOfFrames
                    *
                    conversionRatio);
            
            this.numColumns = BuildGridGUI2.this.numCols;
            
            this.numRows = (int)(
                    (
                            (double)BuildGridGUI2.this.numFrames
                            /
                            numColumns
                    )
                    + 0.5);
        }
        
    }
    
}

实际的源代码(不严格相关,但是如果你有心情回顾代码,那么我很乐意学习更好的编码惯例。)

谢谢大家!


共2个答案

匿名用户

所有的侧边栏组件都画在左上角,同时仍然在侧边栏上显示/运行;

JComponent是所有Swing组件都扩展的抽象类。它没有默认的绘画逻辑。

因此,调用super.paintComponent(…)实际上不会做任何事情。

特别是,在进行自定义绘制之前,它不会清除组件的背景。这将导致你看到的绘画作品。

每当您扩展<code>JComponent</code>时,您的逻辑应该是这样的:

protected void paintComponent(Graphics g)
{
    super.paintComponent(g);

    //  clear background

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

    //  do custom painting

    g.setColor( getForeground() );
    ...
}

注意:这就是很多人在Abra提到的简单自定义绘画中重写<code>JPanel</code>的原因。默认情况下,JPanelpaintComponent(…)方法将清除背景。

匿名用户

我对您发布的代码进行了一些更改。

  • 我更改了类<code>Grid</code>,使其扩展了<code>JPanel</code<,而不是<code>JComponent</code〕,因为自定义绘制通常在<code>JPanel</code>上完成
  • 我向类BuildGridGUI2添加了一个类型为grid的实例成员变量grid,而不是创建一个并将其作为参数发送给方法makeSideMenu

这是您的代码,其中包含我的修改(以及我首选的编码风格)。它只是解决了您报告的问题,仅此而已。

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class BuildGridGUI2 {
    static final int WIDTH_MIN = 100;
    static final int WIDTH_MAX = 2000;
    static final int WIDTH_INIT = 520;

    static final int HEIGHT_MIN = 100;
    static final int HEIGHT_MAX = 2000;
    static final int HEIGHT_INIT = 300;

    int widthOfFrames = 255;
    int heightOfFrames = 255;
    int numCols = 3;
    int numFrames = 1;
    Grid  grid;

    private final JComponent makeUI() {
        JPanel p = new JPanel();
        p.setLayout(new BorderLayout());
        grid = new Grid();
        JComponent j = makeSideMenu();
        grid.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.red),
                                                          grid.getBorder()));

        j.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.red),
                                                       j.getBorder()));
        p.add(j, BorderLayout.EAST);
        p.add(grid, BorderLayout.WEST);
        return p;
    }

    private final JComponent makeSideMenu() {
        JPanel p = new JPanel();
        JLabel numColsSelectorLabel = new JLabel("Frames Per Column");
        JSpinner numColsSelectorField = new JSpinner();
        JLabel widthLabel = new JLabel("Width per Frame (Pixels)");
        JSpinner widthSpinner = new JSpinner();
        JSlider widthSlider = new JSlider(WIDTH_MIN, WIDTH_MAX, WIDTH_INIT);
        JLabel heightLabel = new JLabel("Height per Frame (Pixels)");
        JSpinner heightSpinner = new JSpinner();
        JSlider heightSlider = new JSlider(BuildGridGUI2.HEIGHT_MIN,
                                           BuildGridGUI2.HEIGHT_MAX,
                                           BuildGridGUI2.HEIGHT_INIT);
        JButton confirmButton = new JButton("Confirm");
        numColsSelectorField.setEditor(new JSpinner.NumberEditor(numColsSelectorField));
        numColsSelectorField.setMaximumSize(numColsSelectorField.getPreferredSize());
        widthSlider.setMajorTickSpacing(300);
        widthSlider.setMinorTickSpacing(20);
        widthSlider.setPaintTicks(true);
        widthSlider.setPaintLabels(true);
        widthSpinner.setEditor(new JSpinner.NumberEditor(widthSpinner));
        widthSpinner.setPreferredSize(new Dimension(70, 30));
        widthSpinner.setMaximumSize(widthSpinner.getPreferredSize());

        heightSlider.setMajorTickSpacing(300);
        heightSlider.setMinorTickSpacing(20);
        heightSlider.setPaintTicks(true);
        heightSlider.setPaintLabels(true);

        heightSpinner.setEditor(new JSpinner.NumberEditor(heightSpinner));
        heightSpinner.setPreferredSize(new Dimension(70, 30));
        heightSpinner.setMaximumSize(heightSpinner.getPreferredSize());

        confirmButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                widthOfFrames = 200;
                grid.refresh();
            }
        });

        p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
        p.setPreferredSize(new Dimension(300, 480));
        p.setSize(new Dimension(300, 480));

        numColsSelectorLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
        numColsSelectorField.setAlignmentX(Component.CENTER_ALIGNMENT);
        widthSlider.setAlignmentX(Component.CENTER_ALIGNMENT);
        heightSlider.setAlignmentX(Component.CENTER_ALIGNMENT);
        confirmButton.setAlignmentX(Component.CENTER_ALIGNMENT);
        widthLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
        heightLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
        widthSpinner.setAlignmentX(Component.CENTER_ALIGNMENT);
        heightSpinner.setAlignmentX(Component.CENTER_ALIGNMENT);

        p.add(Box.createRigidArea(new Dimension(300, 30)));
        p.add(numColsSelectorLabel);
        p.add(Box.createRigidArea(new Dimension(300, 5)));
        p.add(numColsSelectorField);
        p.add(Box.createRigidArea(new Dimension(300, 25)));
        p.add(widthLabel);
        p.add(Box.createRigidArea(new Dimension(300, 3)));
        p.add(widthSpinner);
        p.add(widthSlider);
        p.add(Box.createRigidArea(new Dimension(300, 25)));
        p.add(heightLabel);
        p.add(Box.createRigidArea(new Dimension(300, 3)));
        p.add(heightSpinner);
        p.add(heightSlider);
        p.add(Box.createRigidArea(new Dimension(300, 45)));
        p.add(confirmButton);
        return p;
    }

    private static void createAndShowGUI() {
        BuildGridGUI2 b = new BuildGridGUI2();
        JFrame mainFrame = new JFrame("Grid Builder");
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.setSize(940, 480);
        mainFrame.getContentPane().add(b.makeUI());
        mainFrame.setResizable(false);
        mainFrame.setVisible(true);
    }

    public static void main(String... args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }

    class Grid extends JPanel {
        static final int CANVAS_WIDTH = 640;
        static final int CANVAS_HEIGHT = 480;

        private final double conversionRatio = 4.0 / 9.0; // 1080p scaled down to 480p preview

        private int squareHeight, squareWidth, numColumns, numRows;

        public Grid() {
            setOpaque(true);
            setSize(CANVAS_WIDTH, CANVAS_HEIGHT); // trying to get the size to work properly.
            setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT);
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            updateVars();
            int k;
            for (k = 0; k < numColumns; k++) {
                // @param: (x1, y1), (x2, y2)
                g.drawLine(k * squareWidth, 0, k * squareWidth, CANVAS_HEIGHT);
            }
            for (k = 0; k < numRows; k++) {
                g.drawLine(0, k * squareHeight, CANVAS_WIDTH, k * squareHeight);
            }
        }

        public void refresh() {
            // Attempting to set the repaint area to only the grid region
            // because CTRL+F is free and parameters are not
            repaint(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
        }

        public void updateVars() {
            this.squareWidth = (int) ((double) BuildGridGUI2.this.widthOfFrames * conversionRatio);
            this.squareHeight = (int) ((double) BuildGridGUI2.this.heightOfFrames * conversionRatio);
            this.numColumns = BuildGridGUI2.this.numCols;
            this.numRows = (int) (((double) BuildGridGUI2.this.numFrames / numColumns) + 0.5);
        }
    }
}

一个提示:尽量使用< code>JComponent的特定子类,而不是< code>JComponent。例如,我建议将方法< code > makesidenumen()的返回类型更改为< code>JPanel而不是< code>JComponent,因为该方法实际上返回一个< code>JPanel。