微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

重绘后 JComponents 移动到原点 计划的意图:结构:

如何解决重绘后 JComponents 移动到原点 计划的意图:结构:

类似于 JButton showing up in the wrong spot after repaint is called,但对该问题的回答仅说明他没有使用布局管理器,而我正在使用布局管理器(很差),所以不幸的是,它并没有真正帮助。

详情

计划的意图:

显示 1920x1080 网格的预览(缩小到 640x480 以节省空间),随着您更改每个正方形的高度、每个正方形的宽度以及它将具有的列数进行拉伸和收缩。 (您首先指定要在网格中的总方块数,因此程序会推断出行数。)

结构:

  • 一个顶级 JFrame。
  • 包含两个 JPanel:Grid 和侧边栏,使用 BorderLayout 将它们对齐到东西两侧。
  • 侧边栏一个 JPanel,包含 Y 轴对齐的 BoxLayout 中的所有 JComponent。
  • Grid 扩展了 JComponent,并使用 Graphics.drawLine() 来绘制网格。
  • 边栏中的每个组件在更改网格时都会调用 Grid.repaint()。

Current UI,with the two main JPanels outlined in red.

问题

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

  1. 网格不清晰,导致出现多条线;
  2. 所有侧边栏组件都在左上角绘制,同时仍然在侧边栏显示/运行;
  3. 出于某种原因,网格将自身调整为比正常情况更宽。

Current UI,but borked.

我的尝试

  1. 将 repaint() 区域更改为仅覆盖网格的矩形,
  2. 检查文档是否有任何相关信息,
  3. 谷歌,
  4. 问你们。

代码

Reprex:(简化为“按按钮重现”,同时仍保留潜在问题区域的本质。)

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,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,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);
        }
        
    }
    
}

Actual Source Code(并非严格相关,但如果您对 code review 感兴趣,那么我很想学习更好的编码约定。)

谢谢!

解决方法

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

  • 我更改了类 Grid,使其扩展 JPanel 而不是 JComponent,因为自定义绘画通常是在 JPanel 上完成的。
  • 我向类 grid 添加了一个类型为 Grid 的实例成员变量 BuildGridGUI2,而不是创建一个并将其作为参数发送给方法 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,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,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);
        }
    }
}

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

,

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

<!-- <span class="backgroundImg"> --> <header> <h1>Maurice Rogers</h1> <nav> <ul class="navbar"> <li class="nav-link"><a class="nav-link" href="index.html">Bio</a></li> <li class="nav-link"><a class="nav-link" href="technical-resume.html">Technical Resume</a>. </li> <li class="nav-link"><a class="nav-link" href="my-animations.html">Animations</a></li> <li class="nav-link"><a class="nav-link" href="me-surfing.html">Surfing</a></li> <li class="nav-link"><a class="nav-link" href="my-art.html">Art</a></li> </ul> </nav> </header> <main> <br/> <h2>My Animations</h2> <br/> <!-- <iframe width="560" height="315" src="https://www.youtube.com/embedvideoseries? list=PL9xPrB7vjr6kZYms6RFtpyPGmZqvNj7MS" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen enablejsapi="1"></iframe> <p>My animations took many hours of hard work to create. Enjoy.</p> --> </main> <footer> <nav> <a class="ftr-nav-link" href="my-animations.html">Back to top</a> </nav> <p>&copy; 2021 Maurice Rogers</p> </footer> <!-- </span> --> 是所有 Swing 组件都从其扩展的抽象类。它没有默认的绘画逻辑。

因此调用 JComponent 并没有真正做任何事情。

特别是在进行自定义绘制之前不会清除组件的背景。这将导致您看到的绘画伪像。

任何时候你扩展 super.paintComponent(...) 你的逻辑应该是这样的:

JComponent

注意:这就是 Abra 提到的许多人为了简单的自定义绘画而覆盖 protected void paintComponent(Graphics g) { super.paintComponent(g); // clear background g.setColor( getBackground() ); g.fillRect(0,getWidth(),getHeight()); // do custom painting g.setColor( getForeground() ); ... } 的原因。 JPanelpaintComponent(...) 方法将默认清除背景。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?