【问题标题】:jsplitpane and paintcomponent conflicting with each otherjsplitpane和paintcomponent相互冲突
【发布时间】:2020-11-28 23:03:34
【问题描述】:

我的代码存在问题,即当我将 City 类实例化为对象并将其添加到 JSplitPane 的右侧(甚至左侧)时,应该绘制的圆圈是没有出现。我的城市类使用paintComponent 并且应该通过调用构造函数来绘制一个圆圈。我也尝试将重绘放在它自己的 drawIt() 方法中,但结果仍然相同。按钮和微调器显示在分隔线的左侧,但我尝试绘制的圆圈根本不显示。

这是我的 City 类。

import javax.swing.*;
import java.awt.*;

public class City extends JPanel{
    int xPos, yPos;
    
    City(int x, int y){
        xPos = x;
        yPos = y;
        repaint();
    }
    
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        
        g.setColor(Color.BLACK);
        g.fillOval(xPos, yPos, 10, 10);
    }
    
}

这是我的主要内容。 在这里,我尝试实例化我的城市并将其添加到 JSplitPane 的右侧(在 Add Components 下),这就是我遇到问题的地方,因为黑色圆圈不会在 JSplitPane 上绘制。

import java.awt.*;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JSplitPane;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;

public class TSP{   
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            
            @Override
            public void run() {
                new TSP();
            }
        });
    }
    
    TSP(){
        JLabel instructions = new JLabel("Enter the number of cities: ");
        instructions.setBounds(30, 150, 300, 40);
        
        SpinnerNumberModel numMod = new SpinnerNumberModel(2, 2, 10, 1);
        JSpinner numOfCities = new JSpinner(numMod);
        numOfCities.setBounds(185, 150, 80, 40);
        
        JButton start = new JButton("Start Simulation");
        start.setBounds(50, 400, 200, 40);
        
        JFrame frame = new JFrame("Travelling Salesperson");
        
        JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        JPanel lp = new JPanel(null);
        JPanel rp = new JPanel(null);
        sp.setDividerLocation(300);
        sp.setLeftComponent(lp);
        sp.setRightComponent(rp);
        sp.setEnabled(false);
            
        frame.setDefaultCloseOperation(3);
        frame.setSize(1100,600);
        frame.setResizable(false);
        ////////////////Add Components//////////////////////////
        lp.add(instructions);
        lp.add(numOfCities);
        lp.add(start);
        
        City test = new City(301, 301);
        rp.add(test);
        
        frame.add(sp);
        ////////////////////////////////////////////////////////    
        
        frame.setVisible(true);
    }

}

我觉得圆圈是在 JSplitPane 下绘制的,就好像我将我的城市对象(测试)添加到我的框架中,而不是添加组件下的 JSplitPane(frame.add(test) 而不是 rp.add(test)部分)黑色圆圈将出现在所需的位置,但 JSplitPane 以及按钮和微调器将消失,所以我觉得它们好像是冲突的。是否有任何解决方法,或者是否有另一种方法可以使圆圈出现在右侧,而其他组件在左侧。 我不知道为什么它没有在 JSplitPane 上绘制圆圈,但任何形式的帮助都将不胜感激。谢谢! 抱歉,如果有任何不清楚的地方或我的代码有任何歧义,或者我需要发布更多信息,因为我是在这里发布的新手。让我知道是否还有其他需要添加的内容,或者对我所问的内容有任何疑问!

编辑: 我画圆圈的地方似乎有什么东西挡住了,比如另一个 JPanel。这是下面的图像。如您所见,圆圈的一部分看起来好像被覆盖了。我画的小盒子是唯一可以看到圆点的区域(在其他任何地方,圆圈都被白色覆盖)。另外,下图中圆圈的坐标在 (3, 0),即 City test = new City(3, 0); 我不太确定为什么会这样。 the invisible JPanel?

【问题讨论】:

  • 再一次,空布局把你搞砸了。正在添加您的 City JPanel,但默认大小为 0,0 - 如果它这么小,怎么能显示?您需要 1) 摆脱空布局,2) 以智能方式覆盖 City 的 `getPreferredSize。 3) 以智能的方式学习和使用布局。
  • 另外,在 City 类的 paintComponent 方法中,drawOval 方法 X 和 Y 与 JPanel 相关,而不是 JSplitPane。为您的 X 和 Y 尝试零。
  • @GilbertLeBlanc 感谢您提供的信息。我按照您所说的进行了尝试,现在黑点位于 JSplitPane 右侧的顶部中心(当我尝试将 0,0 作为 X 和 Y 时)。但似乎在绘制圆圈的上方还有另一个面板。当我将 X 和 Y 1 像素向下移动到一侧时,圆圈的一半(或一部分)似乎被一个空白的 JPanel 覆盖?
  • 我不知道你的 GUI 应该是什么样子。我需要一张图片或一些 ASCII 艺术作品,以便我可以正确发表评论。
  • 抱歉@GilbertLeBlanc,正在添加图片!

标签: java swing jpanel layout-manager null-layout-manager


【解决方案1】:

既然我已经看到了你想要做什么,我可以提供一个更合适的答案。

您在左侧有一个控制面板,在右侧有一个绘图面板。通常,您不使用 JSplitPane 来分隔面板。要创建布局,您需要将控制面板添加到 JFrame BorderLayout 的 LINE_START 并将绘图面板添加到 CENTER。

这样做的原因是您不想不断地重新计算绘图面板的大小。

所以让我向您展示一种获得良好开端的方法。这是我创建的 GUI。

这是我做过的事情。

  1. 所有 Swing GUI 应用程序都必须以调用 SwingUtilities invokeLater 方法开始。此方法确保在Event Dispatch Thread 上创建和执行 Swing 组件。

  2. 我将JFrame、控制面板和绘图面板的创建分开。这样一来,我就可以一次只专注于 GUI 的一部分。

  3. JFrame 方法必须按特定顺序调用。这是我用于大多数 Swing 应用程序的顺序。

  4. JFrame 未调整大小。它是包装好的。 Swing layout managers 将计算组件的大小和JPanels

  5. 我使用FlowLayoutGridBagLayout 来创建控制面板。是的,这看起来比绝对定位更复杂,但从长远来看,布局管理器让 GUI 更加灵活。

  6. 我在绘图面板中使用了setPreferredSize 方法来设置绘图面板的首选大小。因为我知道绘图面板的大小,所以我可以将第一个城市放在绘图面板的中心。

这是代码。您不必完全像这样编写代码,但此代码应该为您启动项目提供了良好的基础。查看model / view / controller pattern,了解如何进一步将您的代码分成更小的部分,让您一次只专注于应用程序的一个部分。

我将所有类放在一个文件中以便于粘贴。您应该将这些类分成单独的文件。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;

public class CitySimulation implements Runnable {

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

    private ControlPanel controlPanel;

    private DrawingPanel drawingPanel;

    private JFrame frame;

    @Override
    public void run() {
        frame = new JFrame("Traveling Salesperson");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        controlPanel = new ControlPanel();
        frame.add(controlPanel.getPanel(), BorderLayout.LINE_START);

        drawingPanel = new DrawingPanel();
        frame.add(drawingPanel, BorderLayout.CENTER);

        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public class ControlPanel {

        private JPanel panel;

        public ControlPanel() {
            panel = new JPanel(new FlowLayout());

            JPanel mainPanel = new JPanel(new GridBagLayout());

            GridBagConstraints gbc = new GridBagConstraints();

            gbc.anchor = GridBagConstraints.LINE_START;
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.insets = new Insets(10, 10, 10, 10);

            JLabel instructions = new JLabel("Enter the number " +
                    "of cities:");
            mainPanel.add(instructions, gbc);

            gbc.gridx++;
            gbc.insets = new Insets(10, 0, 10, 10);

            SpinnerNumberModel numMod =
                    new SpinnerNumberModel(2, 2, 10, 1);
            JSpinner numOfCities = new JSpinner(numMod);
            mainPanel.add(numOfCities, gbc);

            gbc.anchor = GridBagConstraints.CENTER;
            gbc.gridx = 0;
            gbc.gridy++;
            gbc.gridwidth = 2;
            gbc.insets = new Insets(10, 10, 10, 10);

            JButton start = new JButton("Start Simulation");
            mainPanel.add(start, gbc);

            panel.add(mainPanel);
        }

        public JPanel getPanel() {
            return panel;
        }

    }

    public class DrawingPanel extends JPanel {

        private static final long serialVersionUID = 1L;

        public DrawingPanel() {
            this.setBackground(Color.WHITE);
            this.setPreferredSize(new Dimension(400, 400));
        }

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

            g.setColor(Color.BLACK);
            g.fillOval(195, 195, 10, 10);
        }
        
    }

}

【讨论】:

  • 我刚刚有一个关于 ControlPanel 类的简短问题。为什么要在已经存在的面板上添加一个 mainPanel?是否有理由不直接在“面板”上添加所有组件,而不是在“mainPanel”上创建并添加它们,然后将其添加到“面板”上?谢谢!哦,我才意识到一个是FlowLayout,另一个是GridBagLayout。使用 FlowLayout 创建“面板”并将“mainPanel”添加到“面板”上是否有原因?
  • 一个 GridBagLayout 将使 JComponents 在 JPanel 的中心垂直居中。用 FlowLayout JPanel 包围 JPanel 会将 JComponents 移动到 JPanel 的顶部。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-07
  • 2020-06-29
  • 1970-01-01
  • 1970-01-01
  • 2014-08-20
  • 2012-12-29
相关资源
最近更新 更多