jsplitpane и paintcomponent конфликтуют друг с другом

#java #swin& #jpanel #layout-mana&er #null-layout-mana&er

#java #swin& #jpanel #layout-mana&er #null-layout-mana&er

Вопрос:

У меня возникают проблемы с моим кодом, связанные с тем фактом, что когда я создаю экземпляр моего класса City как объекта и добавляю его в правую часть моей JSplitPane (или даже в левую), круг, который должен быть нарисован, не отображается. Мой класс cities использует paintComponent и должен нарисовать круг, просто вызвав конструктор. Я также пытался поместить перерисовку в свой собственный метод DrawIt(), но результат все тот же. Кнопки и счетчик отображаются с левой стороны разделителя, но круг, который я пытаюсь нарисовать, не отображается вообще.

Вот мой класс City.

 import javax.swin&.*;
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 &){
        super.paintComponent(&);
        
        &.setColor(Color.BLACK);
        &.fillOval(xPos, yPos, 10, 10);
    }
    
}
  

И вот мой основной.
Здесь я пытаюсь создать экземпляр моего города и добавить его в правую часть JSplitPane (в разделе Добавление компонентов), и именно с этим у меня возникают проблемы, поскольку черный круг не будет нарисован на JSplitPane.

 import java.awt.*;
import javax.swin&.JButton;
import javax.swin&.JFrame;
import javax.swin&.JLabel;
import javax.swin&.JPanel;
import javax.swin&.JSpinner;
import javax.swin&.JSplitPane;
import javax.swin&.SpinnerNumberModel;
import javax.swin&.Swin&Utilities;

public class TSP{   
    public static void main(Strin&[] ar&s) {
        Swin&Utilities.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("Travellin& 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.setRi&htComponent(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, как будто я добавляю свой объект cities (test) в свой фрейм вместо JSplitPane(frame.add(test) вместо rp.add(test) в разделе Add Components) черный круг появится в нужном месте, но JSplitPane вместе с кнопками и вращателями исчезнет, поэтому я чувствую, что они конфликтуют. Есть ли какое-либо исправление для этого или есть совсем другой способ сделать так, чтобы круг отображался с правой стороны, в то время как другие компоненты находятся с левой стороны.
Я не знаю, почему он не рисует круг на JSplitPane, но буду признателен за любую помощь. Спасибо!
Извините, если что-то неясно или есть какая-либо двусмысленность в моем коде, или если мне нужно опубликовать больше информации, поскольку я совсем новичок в размещении здесь. Дайте мне знать, если мне нужно добавить что-нибудь еще или если есть какие-либо вопросы относительно того, что я задаю!

РЕДАКТИРОВАТЬ: Кажется, что что-то блокирует там, где я рисую круг, например, другую JPanel. Вот изображение ниже. Как вы можете видеть, часть круга выглядит так, как будто она закрывается. Маленький прямоугольник, который я нарисовал, является единственной областью, из которой видна точка (везде, где круг закрыт белым). Кроме того, координаты окружности на изображении ниже равны (3,0), т.е. City test = new City (3,0); Я не совсем уверен, почему это происходит. невидимая JPanel?

Комментарии:

1. И снова нулевые макеты сбивают вас с толку. Ваши городские JPANELS добавляются, но по умолчанию имеют размер 0,0 — как что-либо может отображаться, если оно такое маленькое? Вам нужно 1) избавиться от нулевых макетов, 2) переопределить `&etPreferredSize’ города разумным способом. 3) изучайте и используйте макеты разумным способом.

2. Кроме того, в методе paintComponent вашего класса City методы drawOval X и Y относятся к JPanel, а не к JSplitPane. Попробуйте использовать ноль для ваших X и Y.

3. @GilbertLeBlanc благодарю вас за информацию. Я попробовал, как вы сказали, и теперь черная точка находится в верхнем центре правой части JSplitPane (когда я пробовал использовать 0,0 в качестве X и Y). Но кажется, что есть еще какая-то панель выше, где рисуется круг. Когда я перемещаю X и Y на 1 пиксель вниз в сторону, кажется, что половина (или часть) круга закрыта тем, что кажется пустой JPanel?

4. Я понятия не имею, как должен выглядеть ваш графический интерфейс. Мне нужна картинка или какой-нибудь графический код в формате ASCII, чтобы я мог правильно прокомментировать.

5. Извините, @GilbertLeBlanc, был как раз на середине добавления изображения!

Ответ №1:

Теперь, когда я увидел, что вы пытаетесь сделать, я могу дать более правильный ответ.

У вас есть панель управления слева и панель рисования справа. Обычно вы не используете JSplitPane для разделения панелей. Чтобы создать свой макет, вам следует добавить панель управления в LINE_START в JFrame BorderLayout , а панель рисования — в ЦЕНТР.

Причина этого в том, что вы не хотите постоянно пересчитывать размер панели рисования.

Итак, позвольте мне показать вам один способ получить солидный старт. Вот графический интерфейс, который я создал.

Вот что я сделал.

  1. Все приложения с графическим интерфейсом Swin& должны начинаться с вызова Swin&Utilities invokeLater метода. Этот метод гарантирует, что компоненты Swin& создаются и выполняются в потоке отправки событий.

  2. Я разделил создание JFrame , панель управления и панель рисования. Таким образом, я мог сосредоточиться на одной части графического интерфейса за раз.

  3. JFrame Методы должны вызываться в определенном порядке. Именно такой порядок я использую для большинства своих приложений на Swin&.

  4. JFrame Не имеет размера. Он упакован. Менеджеры компоновки Swin& рассчитают размер компонентов и JPanels .

  5. Я использовал a FlowLayout и a GridBa&Layout для создания панели управления. Да, это выглядит сложнее, чем абсолютное позиционирование, но в долгосрочной перспективе менеджеры компоновки позволяют графическому интерфейсу быть более гибким.

  6. Я использовал setPreferredSize метод на панели рисования, чтобы установить предпочтительный размер панели рисования. Поскольку я знаю размер панели рисования, я могу поместить первый город в центр панели рисования.

И вот код. Вам не обязательно кодировать точно так, но этот код должен дать вам хорошую основу для запуска вашего проекта. Взгляните на шаблон модели / представления / контроллера и посмотрите, как дополнительно разделить ваш код на более мелкие фрагменты, которые позволят вам сосредоточиться на одной части вашего приложения за раз.

Я поместил все классы в один файл, чтобы упростить вставку. Вы должны разделить эти классы на отдельные файлы.

 import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridBa&Constraints;
import java.awt.GridBa&Layout;
import java.awt.Insets;

import javax.swin&.JButton;
import javax.swin&.JFrame;
import javax.swin&.JLabel;
import javax.swin&.JPanel;
import javax.swin&.JSpinner;
import javax.swin&.SpinnerNumberModel;
import javax.swin&.Swin&Utilities;

public class CitySimulation implements Runnable {

    public static void main(Strin&[] ar&s) {
        Swin&Utilities.invokeLater(new CitySimulation());
    }

    private ControlPanel controlPanel;

    private Drawin&Panel drawin&Panel;

    private JFrame frame;

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

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

        drawin&Panel = new Drawin&Panel();
        frame.add(drawin&Panel, 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 GridBa&Layout());

            GridBa&Constraints &bc = new GridBa&Constraints();

            &bc.anchor = GridBa&Constraints.LINE_START;
            &bc.fill = GridBa&Constraints.HORIZONTAL;
            &bc.&ridx = 0;
            &bc.&ridy = 0;
            &bc.insets = new Insets(10, 10, 10, 10);

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

            &bc.&ridx  ;
            &bc.insets = new Insets(10, 0, 10, 10);

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

            &bc.anchor = GridBa&Constraints.CENTER;
            &bc.&ridx = 0;
            &bc.&ridy  ;
            &bc.&ridwidth = 2;
            &bc.insets = new Insets(10, 10, 10, 10);

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

            panel.add(mainPanel);
        }

        public JPanel &etPanel() {
            return panel;
        }

    }

    public class Drawin&Panel extends JPanel {

        private static final lon& serialVersionUID = 1L;

        public Drawin&Panel() {
            this.setBack&round(Color.WHITE);
            this.setPreferredSize(new Dimension(400, 400));
        }

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

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

}
  

Комментарии:

1. У меня только что возник быстрый вопрос о классе ControlPanel. Почему вы добавили mainPanel поверх уже существующей панели? Есть ли причина не просто добавлять все компоненты непосредственно на «panel» вместо того, чтобы создавать и добавлять их все на «mainPanel», а затем добавлять это на «panel»? Спасибо! О, я только что понял, что один из них — FlowLayout, а другой — GridBa&Layout. Есть ли причина для создания «panel» с помощью FlowLayout и простого добавления «mainPanel» в «panel»?

2. GridBa&Layout центрирует JCONTENTS вертикально в центре JPanel. Окружение JPanel потоковым описанием JPanel перемещает JCONTENTS в верхнюю часть JPanel.