Добавление панели без макета к СЕВЕРУ от BorderLayout

Коллеги.

Я пытаюсь создать простой графический интерфейс на Java, где JFrame имеет макет границы. Я хочу поместить JScrollPane с JTable в ЦЕНТР, а JPanel без макета - в СЕВЕР.

Проблема в том, что JPanel не виден. Существует простой пример проблемы:

JFrame frame = new JFrame("Test frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

JButton button = new JButton("Test button");
button.setBounds(10, 10, 40, 20);

JPanel panelN = new JPanel(null); // layout = null, panelN without layout
panelN.add(button);
frame.add(panelN, BorderLayout.NORTH);

JTable table = new JTable(new DefaultTableModel(4, 4));
JScrollPane scrollPane = new JScrollPane(table);
frame.add(scrollPane, BorderLayout.CENTER);

frame.setSize(400, 400);
frame.setVisible(true);

person Dumas45    schedule 18.06.2013    source источник
comment
использовать layoutManager на панели   -  person nachokk    schedule 18.06.2013
comment
@ dumas45 dumas45, нет веских причин использовать нулевой макет. Используйте Swing так, как он был разработан, и используйте менеджер компоновки.   -  person camickr    schedule 18.06.2013
comment
Проблема в том, что в диспетчере компоновки родительский контейнер не знает, какого размера сделать дочернюю панель, поэтому он получает размер 0x0, который является размером по умолчанию для компонента.   -  person MadProgrammer    schedule 19.06.2013
comment
Я обнаружил, что метод setPreferredSize помогает, и панель становится видимой. если я использую JFrame.setDefaultLookAndFeelDecorated(true); перед созданием графического интерфейса, я надеюсь, что графический интерфейс будет таким же в Linux, Windows и других ОС. Не так ли?   -  person Dumas45    schedule 19.06.2013


Ответы (4)


Вы должны использовать LayoutManager. Совершенно не рекомендуется использовать layoutManager, но если вы хотите этого, вы также должны установить panel.setBounds(..) на панель.

По умолчанию JPanel имеет FlowLayout, поэтому, если вы поместите

JPanel panelN = new JPanel(); // FlowLayout used 
panelN.add(button);
frame.add(panelN, BorderLayout.NORTH);

Таким образом, ваша рамка будет выглядеть так.

пример

Менеджеры компоновки определяют размер и положение компонентов внутри контейнера. Хотя компоненты могут предоставлять подсказки по размеру и выравниванию, последнее слово о размере и положении компонентов в контейнере остается за менеджером компоновки контейнера.

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

person nachokk    schedule 18.06.2013

Я не знаю ожидаемого поведения нулевого макета, но без дополнительных требований вы можете просто создать экземпляр с помощью конструктора с нулевым аргументом:

new JPanel();
person Davey Chu    schedule 18.06.2013
comment
Я хочу использовать абсолютное позиционирование в JPanel, например, описание там [ссылка]docs .oracle.com/javase/tutorial/uiswing/layout/none.html - person Dumas45; 18.06.2013
comment
@ Dumas45 Тогда вам нужно понять, что вы теряете, не используя менеджер компоновки. - person MadProgrammer; 19.06.2013

Если вы не установили какой-либо макет для панели, при добавлении компонентов панель не знает, куда поместить компонент, поэтому, по сути, компонент не отображается, пока вы не установите определенное местоположение для компонентов. один за другим методом component.setBounds(x,y,width,hieght).

Обратите внимание, что не рекомендуется удалять менеджер компоновки из-за разных платформ, предположим, что ваша программа работает на Window, MacOS и Linux, вместо этого вам лучше использовать менеджеры компоновки.

Взгляните на этот пост также и см. комментарий @Andrew Thompson к моему ответу:

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

В конце концов: если у вас есть требование или задание, говорящее вам, что вы должны использовать абсолютный макет, используйте его, в противном случае избегайте его.

person Azad    schedule 18.06.2013
comment
Я понятия не имею, почему это получило два голоса. Это все еще не помогает ОП. Проблема заключается в добавлении панели на СЕВЕР. Это решение не помогает. Это еще одна причина, по которой не следует использовать нулевой макет. Слишком много ручного кодирования нужно сделать, и люди не знают обо всех маленьких проблемах. Суть в том, что правильный ответ должен заключаться в использовании менеджера компоновки. - person camickr; 18.06.2013
comment
@camickr: я упомянул решение, но вы не думаете, что рассказ об отрицательной стороне его требования будет полезен? - person Azad; 18.06.2013
comment
Проблема в том, что p по умолчанию имеет предпочтительный размер 0x0, просто повезло, что контейнер, в который вы добавили p, использует менеджер компоновки, который не использует предпочтительный размер своих дочерних компонентов для определения результатов компоновки - все та же проблема, с которой сталкивается ОП - ничего не решает - person MadProgrammer; 19.06.2013
comment
@MadProgrammer: моя ошибка, этот пример был для кнопки внутри рамки, а не для панели, спасибо, я отредактировал его. - person Azad; 19.06.2013
comment
На самом деле теперь я думаю, что это хуже - person MadProgrammer; 19.06.2013
comment
@MadProgrammer: да, но это требование OP не использовать какой-либо менеджер компоновки. - person Azad; 19.06.2013
comment
Если бы ОП требовал стрелять себе в ногу, они бы им все равно помогали? - person MadProgrammer; 19.06.2013
comment
Извините за такую ​​боль, но ОП еще не объяснил причину, по которой они хотят использовать абсолютный макет, и пока они не смогут предоставить для этого вескую причину, мы должны сделать все возможное, чтобы направить их к решению, которое их не будет не хватает ноги на финише ;) - person MadProgrammer; 19.06.2013
comment
@MadProgrammer: добро пожаловать, я всегда прислушиваюсь к вашим очень хорошим советам, спасибо :) - person Azad; 19.06.2013

Можно использовать контейнеры без менеджера компоновки, потому что на самом деле вы МОЖЕТЕ установить компоновку контейнера в NULL. И это хорошая идея позиционировать ваши компоненты с помощью setBounds(). Но в этом случае вам просто нужно рассмотреть свой контейнер. Какого размера он должен быть? Менеджер компоновки рассчитает это для вас, и если у вас его нет, вы должны сами установить размер своей панели в соответствии с компонентами, которые вы добавили в нее.

Как указывали другие здесь, в случае, если менеджеру компоновки границ вашего фрейма нужен предпочтительный размер вашей панели NORTH (фактически, предпочтительная высота). И вы должны установить его, иначе значения будут равны нулю, и контейнер станет невидимым. Обратите внимание, что для ЦЕНТРАЛЬНОЙ панели в этом нет необходимости, так как она занимает все возможное пространство.

У меня была проблема, подобная вашей, и я написал быструю функцию для изменения размера контейнера в соответствии с границами данного компонента. Он будет настолько большим, насколько необходимо, чтобы показать этот компонент, поэтому учитываются размер (w, h) и положение (x, y). Существует версия с автоматическим изменением размера, которую можно использовать один раз после добавления всех компонентов.

public static void updatePreferredSize(Container cont, Component comp) {

    int w = cont.getPreferredSize().width;
    int h = cont.getPreferredSize().height;

    int W = comp.getBounds().x + comp.getBounds().width;
    int H = comp.getBounds().y + comp.getBounds().height;

    if (W>w||H>h) cont.setPreferredSize(new Dimension(W>w?W:w, H>h?H:h));
}

public static void autoPreferredSize(Container cont) {

    for (Component comp : cont.getComponents())
        updatePreferredSize(cont, comp);
}

Вы можете использовать updatePreferredSize() после добавления каждого компонента на панель или использовать autoPreferredSize() один раз после всех добавлений.

// [...]
panelN.add(button);
updatePreferredSize(panelN, button);
// [...]

// or...

// [...]
autoPreferredSize(panelN);
// [...]
frame.setVisible(true);

Таким образом, если вы не установите фиксированное значение высоты северной панели, с помощью этих функций вы можете ожидать, что ваша кнопка будет видна в соответствии с положением, которое вы установили с помощью setBounds().

person PFROLIM    schedule 03.11.2016