#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
, а панель рисования — в ЦЕНТР.
Причина этого в том, что вы не хотите постоянно пересчитывать размер панели рисования.
Итак, позвольте мне показать вам один способ получить солидный старт. Вот графический интерфейс, который я создал.
Вот что я сделал.
-
Все приложения с графическим интерфейсом Swin& должны начинаться с вызова
Swin&Utilities
invokeLater
метода. Этот метод гарантирует, что компоненты Swin& создаются и выполняются в потоке отправки событий. -
Я разделил создание
JFrame
, панель управления и панель рисования. Таким образом, я мог сосредоточиться на одной части графического интерфейса за раз. -
JFrame
Методы должны вызываться в определенном порядке. Именно такой порядок я использую для большинства своих приложений на Swin&. -
JFrame
Не имеет размера. Он упакован. Менеджеры компоновки Swin& рассчитают размер компонентов иJPanels
. -
Я использовал a
FlowLayout
и aGridBa&Layout
для создания панели управления. Да, это выглядит сложнее, чем абсолютное позиционирование, но в долгосрочной перспективе менеджеры компоновки позволяют графическому интерфейсу быть более гибким. -
Я использовал
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.