Как динамически управлять компонентами автоматического изменения размера в Java Swing
Создание нового графического интерфейса в Java (1.8) Swing, я ищу способ переопределить поведение всех моих компонентов.
Позвольте мне объяснить вам некоторые отредактированные фотографии:
1. Полноэкранный графический интерфейс
Это мой полноэкранный графический интерфейс с 3 панелями и JToolBar
. Зеленый цвет должен иметь фиксированный размер , остальные будут изменяться по размеру.
В настоящее время у меня есть только 2 маленьких GridLayout
, чтобы организовать их (один вертикальный и один горизонтальный для зеленых и голубых панелей).
![FullScreen GUI]()
2. Небольшое горизонтальное изменение размера
Если я, например, уменьшу размер кадра с правой стороны, я хочу, чтобы моя синяя и голубая панель была изменена размером в соответствии с новым размером кадра. Но зеленая панель должна быть фиксированной. (Не самая сложная часть, которую я думаю.)
![Resized once GUI]()
3. Минимальный горизонтальный размер
Это самая трудная часть для меня. Как только голубая (или голубая) панель достигает минимального размера, я хочу, чтобы он " нажимал" зеленую панель влево, даже если она исчезает с кадра.
Конечно, потянув рамку вправо, снова появится зеленая панель.
![Minimum size of the GUI]()
Как я могу это сделать?
Я подумал об использовании JSplitPane
или конкретного слушателя, чтобы вручную определить поведение изменения размера, но мне нужен совет.
Извините, если существующее сообщение может ответить на этот вопрос, я не нашел ответа, объясняющего эту проблему для меня.
Спасибо заранее!
Если вы хотите больше примеров, посмотрите на программное обеспечение "Evernote", которое действует одинаково.
Ответы
Ответ 1
Установка максимального/минимального/предпочтительного размера панели Green
позволяет сохранить эту панель в том же размере в первом состоянии. Чтобы проверить размер, вы можете использовать ComponentListener
на одном из других JPanel
- если размер становится ниже определенной ширины, измените максимальный/минимальный/предпочтительный размер панели Green
.
Ниже приведен взломанный пример этого - он изменяет размер панели Green
, когда Blue
является < 600, а изменение размера - взвешенное изменение размера (30% от общей ширины). Чтобы получить истинный L & F и что вы хотите, вам, возможно, придется играть с макетом/размерами.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
public class GridTest extends JPanel{
private boolean changeAllowed = false;
//keep reference to cyan for the height dimension
final JPanel cyan = new JPanel();
public GridTest(){
cyan.setPreferredSize(new Dimension(600, 300));//provide sizing hint
}
private Dimension getCustomDimensions(){
if ( changeAllowed ){
return new Dimension((int)(super.getParent().getBounds().width * 0.3), cyan.getBounds().height);
}else{
return new Dimension(200, cyan.getBounds().height);
}
}
@Override
public Dimension getMaximumSize(){
return getCustomDimensions();
}
@Override
public Dimension getMinimumSize(){
return getCustomDimensions();
}
@Override
public Dimension getPreferredSize(){
return getCustomDimensions();
}
public static void main(String[] args) throws Exception{
SwingUtilities.invokeAndWait(new Runnable(){
@Override
public void run() {
final int MINIMUM = 600;
JFrame frame = new JFrame();
frame.add(new JToolBar(), BorderLayout.NORTH);
final JPanel blue = new JPanel();
final GridTest green = new GridTest();
green.setBackground(Color.green);
green.setOpaque(true);
green.cyan.setBackground(Color.cyan);
green.cyan.setOpaque(true);
blue.setOpaque(true);
blue.setBackground(Color.blue);
blue.setPreferredSize(new Dimension(900, 300));//hint at size
blue.setMinimumSize(new Dimension(100, 200));//hint at size
//Nest Box Layouts
Box top = Box.createHorizontalBox();
top.add(blue);
Box bottom = Box.createHorizontalBox();
bottom.add(green);
bottom.add(green.cyan);
Box vert = Box.createVerticalBox();
vert.add(top);
vert.add(bottom);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(vert);
//listen for resizes
blue.addComponentListener(new ComponentAdapter(){
@Override
public void componentResized(ComponentEvent e) {
if ( blue.getBounds().width < MINIMUM ){//set flag
green.changeAllowed = true;
}else{
green.changeAllowed = false;
}
}
});
frame.pack();
frame.setSize(800, 600);
frame.setVisible(true);
}
});
}
}
Ответ 2
Это должно быть легко с помощью GridBagLayout, если вы установите соответствующие минимальные размеры для зеленых и голубых компонентов:
setLayout(new GridBagLayout());
green.setMnimumSize(new Dimension(0, 0));
cyan.setMinimumSize(new Dimension(100, 100)); // whatever fits
add(blue, new GridBagConstraints(0, 0, 2, 1,
1.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0), 0, 0);
add(green, new GridBagConstraints(0, 1, 1, 1,
0.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.NONE,
new Insets(0, 0, 0, 0), 0, 0);
add(cyan, new GridBagConstraints(1, 1, 1, 1,
1.0, 0.0,
GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0), 0, 0);
Указав вес x для голубого и голубого компонента, а также установив resize = HORIZONTAL, они изменяют размер с помощью контейнера.
Ответ 3
Вы можете использовать BoxLayout
для размещения зеленой и голубой панели. A BoxLayout
соответствует минимальному и максимальному размерам компонента. Таким образом, для зеленой панели вы устанавливаете максимальный размер, равный предпочитаемому размеру, а для голубой панели вы устанавливаете минимальный размер, равный предпочитаемому размеру:
import java.awt.*;
import java.util.*;
import javax.swing.*;
public class SSCCE extends JPanel
{
public SSCCE()
{
JPanel blue = new JPanel();
blue.setBackground( Color.BLUE );
blue.setPreferredSize( new Dimension(500, 100) );
Box box = Box.createHorizontalBox();
JPanel green = new JPanel();
green.setBackground( Color.GREEN );
green.setPreferredSize( new Dimension(200, 100) );
green.setMaximumSize( green.getPreferredSize() );
box.add( green );
JPanel cyan = new JPanel();
cyan.setBackground( Color.CYAN );
cyan.setPreferredSize( new Dimension(300, 100) );
cyan.setMinimumSize( cyan.getPreferredSize() );
box.add( cyan );
setLayout( new BorderLayout() );
add(blue, BorderLayout.NORTH);
add(box, BorderLayout.CENTER);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SSCCE());
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
Конечно, правильное решение состоит в том, чтобы переопределить методы getMaximumSize()
и getMinimumSize()
соответственно каждой панели, чтобы просто вернуть предпочтительный размер панели.
Ответ 4
Вот как я это делаю, и я не уверен, что это правильный способ:
Сначала установите для макета значение null.
Далее создайте событие для изменения размера для вашего фрейма:
addComponentListener(new ComponentAdapter(){
public void componentResized(ComponentEvent e){
}
});
Внутри вы можете вручную внести изменения в компоненты по мере их изменения. Я сделал это для нескольких моих программ, чтобы держать панель прокрутки слева и справа от рамки всегда той же ширины и иметь все остальные размеры вверх и вниз по мере изменения размера.
Ответ 5
Важная последовательность такова:
frame.revalidate();
frame.pack();
frame.repaint();
- revalidate(): аннулирует компоненты до ближайшего корня, после чего проверяется иерархия , начиная с ближайшего корня подтверждения.
- pack(): вызывает размер окна, чтобы он соответствовал предпочтительным размерам и макетам его подкомпонентов. Полученная ширина и высота окна автоматически увеличиваются.
- repaints(): после всех повторных вычислений перекраска показывает компоненты.
Используйте эту последовательность после каждой серии изменений, которые вы сделали в своем коде, и хотите увидеть результаты, появляющиеся на экране.
Мне нравится java.awt.GridBagLayout в сочетании с java.awt.GridBagConstraints, и я использую этот макет для всех контейнеров, начиная с области содержимого.
Если вы добавляете контейнер в другой контейнер, используйте макет для каждого из них, иначе вычисление завершится неудачно из-за недостающего макета в иерархии.