Most layout managers work best with a component’s preferredSize, and most GUI’s are best off allowing the components they contain to set their own preferredSizes based on their content or properties. To use these layout managers to their best advantage, do call pack() on your top level containers such as your JFrames before making them visible as this will tell these managers to do their actions — to layout their components.
Often when I’ve needed to play a more direct role in setting the size of one of my components, I’ll override getPreferredSize and have it return a Dimension that is larger than the super.preferredSize (or if not then it returns the super’s value).
For example, here’s a small drag-a-rectangle app that I created for another question on this site:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MoveRect extends JPanel {
private static final int RECT_W = 90;
private static final int RECT_H = 70;
private static final int PREF_W = 600;
private static final int PREF_H = 300;
private static final Color DRAW_RECT_COLOR = Color.black;
private static final Color DRAG_RECT_COLOR = new Color(180, 200, 255);
private Rectangle rect = new Rectangle(25, 25, RECT_W, RECT_H);
private boolean dragging = false;
private int deltaX = 0;
private int deltaY = 0;
public MoveRect() {
MyMouseAdapter myMouseAdapter = new MyMouseAdapter();
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (rect != null) {
Color c = dragging ? DRAG_RECT_COLOR : DRAW_RECT_COLOR;
g.setColor(c);
Graphics2D g2 = (Graphics2D) g;
g2.draw(rect);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private class MyMouseAdapter extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
Point mousePoint = e.getPoint();
if (rect.contains(mousePoint)) {
dragging = true;
deltaX = rect.x - mousePoint.x;
deltaY = rect.y - mousePoint.y;
}
}
@Override
public void mouseReleased(MouseEvent e) {
dragging = false;
repaint();
}
@Override
public void mouseDragged(MouseEvent e) {
Point p2 = e.getPoint();
if (dragging) {
int x = p2.x + deltaX;
int y = p2.y + deltaY;
rect = new Rectangle(x, y, RECT_W, RECT_H);
MoveRect.this.repaint();
}
}
}
private static void createAndShowGui() {
MoveRect mainPanel = new MoveRect();
JFrame frame = new JFrame("MoveRect");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Note that my main class is a JPanel, and that I override JPanel’s getPreferredSize:
public class MoveRect extends JPanel {
//.... deleted constants
private static final int PREF_W = 600;
private static final int PREF_H = 300;
//.... deleted fields and constants
//... deleted methods and constructors
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
Also note that when I display my GUI, I place it into a JFrame, call pack(); on the JFrame, set its position, and then call setVisible(true); on my JFrame:
private static void createAndShowGui() {
MoveRect mainPanel = new MoveRect();
JFrame frame = new JFrame("MoveRect");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Here is a full mouse adapter i am using for a long time now:
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
/**
* @see http://stackoverflow.com/a/12456113/909085
*/
public class WindowResizeAdapter extends MouseAdapter implements SwingConstants
{
private boolean resizing = false;
private int prevX = -1;
private int prevY = -1;
private int resizeSide = 0;
public static void install ( Component component, int resizeSide )
{
WindowResizeAdapter wra = new WindowResizeAdapter ( resizeSide );
component.addMouseListener ( wra );
component.addMouseMotionListener ( wra );
}
public WindowResizeAdapter ( int resizeSide )
{
super ();
this.resizeSide = resizeSide;
}
public void mousePressed ( MouseEvent e )
{
if ( SwingUtilities.isLeftMouseButton ( e ) )
{
resizing = true;
}
prevX = e.getXOnScreen ();
prevY = e.getYOnScreen ();
}
public void mouseDragged ( MouseEvent e )
{
if ( prevX != -1 && prevY != -1 && resizing )
{
Window w = SwingUtilities.getWindowAncestor ( e.getComponent () );
Rectangle rect = w.getBounds ();
Dimension dim;
boolean undecorated;
if ( w instanceof JDialog )
{
dim = ( ( JDialog ) w ).getContentPane ().getPreferredSize ();
undecorated = ( ( JDialog ) w ).isUndecorated ();
}
else if ( w instanceof JFrame )
{
dim = ( ( JFrame ) w ).getContentPane ().getPreferredSize ();
undecorated = ( ( JFrame ) w ).isUndecorated ();
}
else
{
dim = w.getPreferredSize ();
undecorated = true;
}
// Checking for minimal width and height
int xInc = e.getXOnScreen () - prevX;
int yInc = e.getYOnScreen () - prevY;
if ( undecorated )
{
if ( resizeSide == SwingConstants.NORTH_WEST || resizeSide == SwingConstants.WEST ||
resizeSide == SwingConstants.SOUTH_WEST )
{
if ( rect.width - xInc < dim.width )
{
xInc = 0;
}
}
else if ( resizeSide == SwingConstants.NORTH_EAST ||
resizeSide == SwingConstants.EAST ||
resizeSide == SwingConstants.SOUTH_EAST )
{
if ( rect.width + xInc < dim.width )
{
xInc = 0;
}
}
if ( resizeSide == SwingConstants.NORTH_WEST ||
resizeSide == SwingConstants.NORTH ||
resizeSide == SwingConstants.NORTH_EAST )
{
if ( rect.height - yInc < dim.height )
{
yInc = 0;
}
}
else if ( resizeSide == SwingConstants.SOUTH_WEST ||
resizeSide == SwingConstants.SOUTH ||
resizeSide == SwingConstants.SOUTH_EAST )
{
if ( rect.height + yInc < dim.height )
{
yInc = 0;
}
}
}
// Resizing window if any changes are done
if ( xInc != 0 || yInc != 0 )
{
if ( resizeSide == SwingConstants.NORTH_WEST )
{
w.setBounds ( rect.x + xInc, rect.y + yInc, rect.width - xInc,
rect.height - yInc );
}
else if ( resizeSide == SwingConstants.NORTH )
{
w.setBounds ( rect.x, rect.y + yInc, rect.width, rect.height - yInc );
}
else if ( resizeSide == SwingConstants.NORTH_EAST )
{
w.setBounds ( rect.x, rect.y + yInc, rect.width + xInc, rect.height - yInc );
}
else if ( resizeSide == SwingConstants.WEST )
{
w.setBounds ( rect.x + xInc, rect.y, rect.width - xInc, rect.height );
}
else if ( resizeSide == SwingConstants.EAST )
{
w.setBounds ( rect.x, rect.y, rect.width + xInc, rect.height );
}
else if ( resizeSide == SwingConstants.SOUTH_WEST )
{
w.setBounds ( rect.x + xInc, rect.y, rect.width - xInc, rect.height + yInc );
}
else if ( resizeSide == SwingConstants.SOUTH )
{
w.setBounds ( rect.x, rect.y, rect.width, rect.height + yInc );
}
else if ( resizeSide == SwingConstants.SOUTH_EAST )
{
w.setBounds ( rect.x, rect.y, rect.width + xInc, rect.height + yInc );
}
prevX = e.getXOnScreen ();
prevY = e.getYOnScreen ();
}
}
}
public void mouseReleased ( MouseEvent e )
{
resizing = false;
}
}
Just use its «install» method to add the window resize behavior to any Component. The resizeSide variable is used to define which side of the window should be resized (for example SwingConstants.SOUTH_EAST will force the component to resize bottom right corner of the window).
Edit: You might also want to modify the code for your specific case so that drag (resize) will start only from some specific area on the component. Just modify the mousePressed method to do that.
Here is a full mouse adapter i am using for a long time now:
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
/**
* @see http://stackoverflow.com/a/12456113/909085
*/
public class WindowResizeAdapter extends MouseAdapter implements SwingConstants
{
private boolean resizing = false;
private int prevX = -1;
private int prevY = -1;
private int resizeSide = 0;
public static void install ( Component component, int resizeSide )
{
WindowResizeAdapter wra = new WindowResizeAdapter ( resizeSide );
component.addMouseListener ( wra );
component.addMouseMotionListener ( wra );
}
public WindowResizeAdapter ( int resizeSide )
{
super ();
this.resizeSide = resizeSide;
}
public void mousePressed ( MouseEvent e )
{
if ( SwingUtilities.isLeftMouseButton ( e ) )
{
resizing = true;
}
prevX = e.getXOnScreen ();
prevY = e.getYOnScreen ();
}
public void mouseDragged ( MouseEvent e )
{
if ( prevX != -1 && prevY != -1 && resizing )
{
Window w = SwingUtilities.getWindowAncestor ( e.getComponent () );
Rectangle rect = w.getBounds ();
Dimension dim;
boolean undecorated;
if ( w instanceof JDialog )
{
dim = ( ( JDialog ) w ).getContentPane ().getPreferredSize ();
undecorated = ( ( JDialog ) w ).isUndecorated ();
}
else if ( w instanceof JFrame )
{
dim = ( ( JFrame ) w ).getContentPane ().getPreferredSize ();
undecorated = ( ( JFrame ) w ).isUndecorated ();
}
else
{
dim = w.getPreferredSize ();
undecorated = true;
}
// Checking for minimal width and height
int xInc = e.getXOnScreen () - prevX;
int yInc = e.getYOnScreen () - prevY;
if ( undecorated )
{
if ( resizeSide == SwingConstants.NORTH_WEST || resizeSide == SwingConstants.WEST ||
resizeSide == SwingConstants.SOUTH_WEST )
{
if ( rect.width - xInc < dim.width )
{
xInc = 0;
}
}
else if ( resizeSide == SwingConstants.NORTH_EAST ||
resizeSide == SwingConstants.EAST ||
resizeSide == SwingConstants.SOUTH_EAST )
{
if ( rect.width + xInc < dim.width )
{
xInc = 0;
}
}
if ( resizeSide == SwingConstants.NORTH_WEST ||
resizeSide == SwingConstants.NORTH ||
resizeSide == SwingConstants.NORTH_EAST )
{
if ( rect.height - yInc < dim.height )
{
yInc = 0;
}
}
else if ( resizeSide == SwingConstants.SOUTH_WEST ||
resizeSide == SwingConstants.SOUTH ||
resizeSide == SwingConstants.SOUTH_EAST )
{
if ( rect.height + yInc < dim.height )
{
yInc = 0;
}
}
}
// Resizing window if any changes are done
if ( xInc != 0 || yInc != 0 )
{
if ( resizeSide == SwingConstants.NORTH_WEST )
{
w.setBounds ( rect.x + xInc, rect.y + yInc, rect.width - xInc,
rect.height - yInc );
}
else if ( resizeSide == SwingConstants.NORTH )
{
w.setBounds ( rect.x, rect.y + yInc, rect.width, rect.height - yInc );
}
else if ( resizeSide == SwingConstants.NORTH_EAST )
{
w.setBounds ( rect.x, rect.y + yInc, rect.width + xInc, rect.height - yInc );
}
else if ( resizeSide == SwingConstants.WEST )
{
w.setBounds ( rect.x + xInc, rect.y, rect.width - xInc, rect.height );
}
else if ( resizeSide == SwingConstants.EAST )
{
w.setBounds ( rect.x, rect.y, rect.width + xInc, rect.height );
}
else if ( resizeSide == SwingConstants.SOUTH_WEST )
{
w.setBounds ( rect.x + xInc, rect.y, rect.width - xInc, rect.height + yInc );
}
else if ( resizeSide == SwingConstants.SOUTH )
{
w.setBounds ( rect.x, rect.y, rect.width, rect.height + yInc );
}
else if ( resizeSide == SwingConstants.SOUTH_EAST )
{
w.setBounds ( rect.x, rect.y, rect.width + xInc, rect.height + yInc );
}
prevX = e.getXOnScreen ();
prevY = e.getYOnScreen ();
}
}
}
public void mouseReleased ( MouseEvent e )
{
resizing = false;
}
}
Just use its «install» method to add the window resize behavior to any Component. The resizeSide variable is used to define which side of the window should be resized (for example SwingConstants.SOUTH_EAST will force the component to resize bottom right corner of the window).
Edit: You might also want to modify the code for your specific case so that drag (resize) will start only from some specific area on the component. Just modify the mousePressed method to do that.
Афоризм
Да, я тебе верна. И очень часто.
Поддержка проекта
Если Вам сайт понравился и помог, то будем признательны за Ваш «посильный» вклад в его поддержку и развитие
• Yandex.Деньги
410013796724260
• Webmoney
R335386147728
Z369087728698
Окна являются основой пользовательского интерфейса любой операционной системы. Они визуально
разделяют выполняемые в среде приложения. Окна, используемые в библиотеке Swing, мало чем
отличаются от окон библиотеки AWT, которые представляют собой окна операционной системы.
Все окна библиотеки Swing — а к ним относятся окно без рамки JWindow, окно с рамкой
JFrame и диалоговое окно JDialog — являются исключением из правила, согласно
которому все компоненты Swing представляют собой легковесные компоненты и унаследованы от
базового класса JComponent. Окна Swing являются тяжеловесными контейнерами для размещения в них
легковесных компонентов, которые операционная система не видит.
Наиболее полезные JFrame методы
| Методы | Описание |
|---|---|
| setLocation() | Эта группа методов позволяет задать позицию и размеры окна на экране. setLocation() задает позицию окна, setSize() позволяет указать его размеры, а с помощью setBounds() можно сразу задать прямоугольник, который займет ваше окно на экране |
| setSize() | |
| setBounds() | |
| раск() | Позволяет «упаковать» имеющиеся в окне компоненты, так чтобы они занимали столько места, сколько им необходимо. Компоненты при вызове этого метода переходят в «видимое» состояние, хотя и не появляются на экране до вызова одного из следующих методов |
| show() | Отображение окна на экране. После вызова этих методов компоненты переходят в «видимое» состояние и начинают обслуживаться очередью событий. Метод show() к тому же проводит валидацию содержащихся в окне компонентов |
| setVisible() | |
| dispose() | Убирает окно с экрана (если оно в момент вызова метода видимо) и освобождает все принадлежащие ему ресурсы. |
Окно JWindow
«Родителем» всех окон Swing является окно без рамки и без элементов управления
JWindow.
Класс JWindow представляет собой окно без рамки и без элементов управления,
предназначенных, к примеру, для его закрытия или перемещения. Данный тип окна дает минимальные
возможности по своей настройке, в отличие от чаще всего используемого окна JFrame. Окно без
рамки не часто требуется в программах. Однако в отдельных случаях оно может быть полезно,
особенно в тех случаях, когда необходимо ненадолго вывести на экран какую-либо информацию типа
заставки программы или подсказку для пользователя, и управлять окном с этой информацией не
нужно.
Окна JWindow используются всплывающими меню JPopupMenu в тех ситуациях, когда в
окне приложения не хватает места для размещения легковесного компонента в слое POPUP_LAYER
многослойной панели, где всплывающие меню располагаются по умолчанию. В такой ситуации
вместо легковесного компонента создается небольшое окно без рамки JWindow, которое можно
разместить в любом месте экрана, потому что оно принадлежит операционной системе. В этом окне и
размещается всплывающее меню.
Рассмотрим пример JWindowTest. Основная идея использования окна без рамки JWindow
заключается в копировании части «изображения рабочего стола» в окно приложения. Благодаря
появившемуся в пакете JDK 1.3 классу Robot можно «снимать» экранную копию рабочего стола.
Пример JWindow
// Пример использования окна без рамки JWindow
import javax.swing.*;
import java.awt.*;
// Класс прорисовки изображения
class ImageDraw extends JComponent
{
private Image capture;
ImageDraw (Image capture) {
this.capture = capture;
}
public void paintComponent(Graphics g) {
// Прорисовка изображения
g.drawImage(capture, 0, 0, this);
}
}
public class JWindowTest extends JWindow
{
// изображение "рабочего стола"
private Image capture;
// Размер окна
private int window_w = 300, window_h = 300;
public JWindowTest() {
super();
// Определение положение окна на экране
setLocation(200, 100);
// Определение размера окна
setSize (window_w, window_h);
try {
// "Вырезаем" часть изображения "рабочего стола"
Robot robot = new Robot();
capture = robot.createScreenCapture(
new Rectangle(5, 5, window_w, window_h));
} catch (Exception ex) { ex.printStackTrace(); }
// Добавляем в интерфейс изображение
getContentPane().add(new ImageDraw(capture));
// Открываем окно
setVisible(true);
try {
// Заканчиваем работу через 10 сек
Thread.currentThread();
Thread.sleep(10000);
} catch (Exception e) { }
System.exit(0);
}
public static void main(String[] args) {
new JWindowTest();
}
}
В этом примере приложение наследуем от окна JWindow, чтобы удобнее вызывать методы
этого класса и добавлять в окно компоненты. Объект Robot необходимо создавать в блоке
try … catch, т.к. его создание может быть запрещено менеджером
безопасности, используемым виртуальной машиной Java. Впрочем, нам нарушение безопасности не грозит,
потому что мы создаем отдельное приложение, а не апплет.
Вырезаем часть изображения «рабочего стола» методом createScreenCapture() в стороне он
местоположения нашего окна. Затем в панель содержимого окна добавляется компонент ImageDraw,
который и отображает вырезанное изображения рабочего стола. После вывода окна на экран программа
засыпает на 10 секунд, а потом заканчивает свою работу.
Скриншот рабочего стола с интерфейсом окна примера JWindow представлен на следующем рисунке.
Прежде чем производить настройку окна, в примере JWindowTest вызывается конструктор базового
класса ключевым словом super() без параметров. На самом деле окна без рамки JWindow
обязательно требуют при создании указывать своего «родителя» — окно с рамкой JFrame,что
не всегда может быть неудобно. Специально для таких случаев в класс JWindow был добавлен
конструктор без параметров, который создает вспомогательное невидимое окно JFrame и использует
его как «родителя». После этого все окна без рамки, созданные таким образом, задействуют только
это окно и экономят ресурсы.
Следует также отметить, что с помощью конструктора без параметров создается окно JWindow,
неспособное получать фокус ввода. Чаще всего именно такое поведение необходимо (ведь панелям
инструментов, всплывающим заставкам и меню фокус ввода не нужен). При необходимости получения
фокуса ввода, используйте метод setFocusableWindowState(true).
Окно JFrame
Окно JFrame наследует свойства класса JWindow и представляет собой наиболее часто
используемое в приложениях окно «общего назначения». Основные отличия окна JFrame от JWindow :
- наличие рамки, которая позволяет изменять размер окна;
- наличие заголовка с названием приложения (заголовок может быть пустым);
- возможность использования системного меню, позволяющее проводить манипуляции
с окном и приложением; - наличие кнопок управления для закрытия и свертывания окна.
Для размещения компонентов пользовательского интерфейса в подавляющем большинстве приложений
применяется класс JFrame. Разработчики Swing определили специальный метод закрытия
окна setDefaultCloseOperation, существенно упрощающий эту операцию. Рассмотрим простой
JFrame пример (JFrameWindowListener) с обработкой события закрытия окна.
JFrame пример
import java.awt.Dimension;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class JFrameWindowListener extends JFrame
{
private static final long serialVersionUID = 1L;
private static int counter = 0; // счетчик
private static JLabel label = null;
private static String TEMPL = "Закрытие окна (попыток %d)";
public JFrameWindowListener ()
{
// Создание окна с заголовком
JFrame frame = new JFrame("JFrameWindowListener");
// Не закрывать окно по нажатию на кнопку с крестиком
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
// Подключение слушателя окна
frame.addWindowListener(new WindowListener() {
public void windowActivated (WindowEvent event) {}
public void windowClosed (WindowEvent event) {}
public void windowDeactivated(WindowEvent event) {}
public void windowDeiconified(WindowEvent event) {}
public void windowIconified (WindowEvent event) {}
public void windowOpened (WindowEvent event) {}
// Метод обработки события "Закрытие окна"
public void windowClosing (WindowEvent event) {
if (++counter == 3) {
event.getWindow().setVisible(false);
System.exit(0);
} else
label.setText(String.format(TEMPL, counter));
}
});
label = new JLabel(String.format(TEMPL, counter));
frame.getContentPane().add(label);
frame.setPreferredSize(new Dimension(250, 80));
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args)
{
JFrame.setDefaultLookAndFeelDecorated(true);
new JFrameWindowListener();
}
}
В примере создается окно JFrame с определением заголовка в конструкторе базового
класса. Для определения титульной строки окна можно также использовать метод setTitle()
класса JFrame.
Прежде чем задать размеры окна и отобразить его на экране, вызывается метод
setDefaultCloseOperation(). Данный метод позволяет указать, какое действие будет произведено
при предварительной обработке события processWindowEvent() перед закрытием окна. По умолчанию
используется константа HIDE_ON_CLOSE, убирающая окно с экрана при его закрытии. Можно
использовать значение EXIT_ON_CLOSE, которое указывает, что при закрытии окна необходимо
закончить работу приложения.
В примере методу setDefaultCloseOperation передается константа DO_NOTHING_ON_CLOSE —
ничего не делать при закрытии окна. К окну JFrame подключается слушатель и обработка
события закрытия окна выполняется в методе windowClosing. Алгоритм обработки построен таким
образом, что окно закрывается при третьей попытке. Номер попытки отображается в метке
интерфейса.
Скриншот рабочего стола с интерфейсом окна нашей программы представлен на следующем рисунке.
Для определения иконки окна необходимо использовать метод setIconImage(). Иконка
располагается на кнопке свернутого окна или в заголовке окна в нормальном состоянии.
Из дополнительных возможностей окна с рамкой JFrame следует упомянуть о его
способности «прятать» свои «украшения»: рамку и элементы управления окном. Делает это метод
JWindow.
События окон, WindowListener, WindowFocusListener
Окна Swing (JWindow, JFrame, JDialog) поддерживают два типа событий :
- WindowListener — позволяет узнать об изменениях в состоянии окна;
- WindowFocusListener — сообщает о получении или потере компонентами окна
фокуса ввода
Полный список методов данных слушателей можно найти в интерактивной документации Java.
В интерфейсе слушателя WindowListener чаще остальных применяют метод
windowClosing, вызываемый системой событий при закрытии окна. Рассмотренный выше
пример наглядно демонстрирует это.
К фрейму JFrame можно подключить слушателя окна, созданного на основе
WindowAdapter (чтобы не реализовывать все определенные в интерфейсе WindowListener
методы) и переопределить метод windowClosing, как это представлено в следующих строках кода :
// Добавляем слушателя событий от окна
frame.addWindowListener (new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
// Потверждение закрытия окна JFrame
int res = JOptionPane.showConfirmDialog(null, "Выйти из программы?");
if (res == JOptionPane.YES_OPTION)
System.exit(0);
}
});
При выходе из программы открывается диалоговое окно в панели JOptionPane и у
пользователя спрашивается подтверждение, действительно ли он желает закончить работу с
приложением. Если ответ положительный, то программа завершает работу.
Диалоговое окно JDialog
Диалоговые окна чаще всего используются в приложениях для получения дополнительной информации
с целью установки параметров приложения, вывода важной вспомогательной/отладочной
информации. Диалоговые окна, как правило, создаются модальными (modal), блокирующими доступ к
остальным окнам приложения, пока пользователь не закончит работу с модальным диалоговым окном.
Модальные диалоговые окна располагаются поверх основного окна приложения. Внешний вид диалоговых
окон мало отличается от окон с рамкой JFrame, но обычно у них меньше элементов управления окна
(чаще всего, имеется только кнопка закрытия окна) и отсутствует системное меню.
В Swing диалоговые окна реализуются классом JDialog, унаследованном от базового класса
окон JWindow и позволяющим создавать как обычные, так и модальные диалоговые окна. JDialog
поддерживает как и JFrame закрытие окна, а в остальном сходен с другими окнами Swing.
При создании диалоговых окон Swing необходимо указать «родительское окно», которым может быть
окно с рамкой JFrame или другое диалоговое окно JDialog. Имеется также конструктор, не
требующий «родительского» окна, но использующий вспомогательное прозрачное окно, о котором было
сказано на странице «Окно без рамки JWindow».
JDialog пример создания диалоговых окон
/**
* Тестовый класс создания диалоговых окон
*/
import javax.swing.*;
import java.awt.event.*;
public class JDialogTest extends JFrame
{
private static final long serialVersionUID = 1L;
public JDialogTest() {
super("DialogWindows");
// Выход из программы при закрытии
setDefaultCloseOperation(EXIT_ON_CLOSE);
// Кнопки для создания диалоговых окон
JButton button1 = new JButton("Немодальное окно");
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JDialog dialog = createDialog("Немодальное", false);
dialog.setVisible(true);
}
});
JButton button2 = new JButton("Модальное окно");
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JDialog dialog = createDialog("Модальное", true);
dialog.setVisible(true);
}
});
// Создание панели содержимого с размещением кнопок
JPanel contents = new JPanel();
contents.add(button1);
contents.add(button2);
setContentPane(contents);
// Определение размера и открытие окна
setSize(350, 100);
setVisible(true);
}
/** Функция создания диалогового окна.
* @param title - заголовок окна
* @param modal - флаг модальности
*/
private JDialog createDialog(String title, boolean modal)
{
JDialog dialog = new JDialog(this, title, modal);
dialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
dialog.setSize(180, 90);
return dialog;
}
public static void main(String[] args)
{
new JDialogTest();
}
}
В примере создаем окно с рамкой JFrame, в панели содержимого которого размещается две
кнопки JButton. По нажатию на кнопки создаются диалоговые окна в отдельном методе createDialog().
Диалоговое окно с заданным заголовком JDialog может быть модальным и немодальным. Программа
позволяет создать несколько немодальных окон одновременно, но только одно модальное. Немодальные
окна не блокируют работу с основным окном приложения. При закрытии диалогового окна используется
константа DISPOSE_ON_CLOSE, удаляющую окно после закрытия.
Интерфейс работы примера JDialog представлен на следующем скриншоте.
Библиотека Swing предоставляет набор стандартных диалоговых окон JDialog для получения и
вывода несложной информации. Прежде чем создавать собственное диалоговое окно, следует
рассмотреть возможность использования стандартного.
Оформление окон
Начиная с JDK 1.4 появилась возможность настраивать так называемое визуальное «оформление»
окон: рамка, элементы управления окном (кнопки закрытия или свертывания), системное меню.
Необходимость этого ощущалась с самых первых выпусков Swing.
Сейчас создание различных интерфейсов окон возможна благодаря усовершенствованиям в
UI-представителе корневой панели JRootPane. UI-представитель позволяет создавать специальные
рамки, заголовок, системное меню и кнопки управления окном, и размещать их в корневой панели
нужным образом, используя специализированный менеджер расположения. Менеджер расположения
контролирует пространство корневой панели. Кроме этого, при новом оформлении окон отключаются
системные элементы окна.
В классах JFrame и JDialog имеется статический метод setDefaultLookAndFeelDecorated(),
обеспечивающий возможность оформления всех создаваемых окон.
Пример оформления окон : JDialog decoration
// Оформление окон Swing
import javax.swing.*;
public class JFrameDecorations
{
public static void main(String[] args)
{
// Подключение украшений для окон
JFrame.setDefaultLookAndFeelDecorated(true);
JDialog.setDefaultLookAndFeelDecorated(true);
// Создание окна с рамкой
JFrame frame = new JFrame("Oкнo с рамкой");
// Определение способа завершения работы программы
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setVisible(true);
// Создание диалогового окна
JDialog dialog = new JDialog(frame, "Диалоговое окно");
// Определение способа завершения работы диалогового окна
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setSize(150, 100);
// Определение типа оформления диалогового окна
dialog.getRootPane().setWindowDecorationStyle(JRootPane.INFORMATION_DIALOG);
dialog.setVisible(true);
}
}
В примере создается простое окно с рамкой и диалоговое окно. Перед создания окон вызывается
метод setDefaultLookAndFeelDecorated(), означающий, что для создаваемых окон JFrame и
JDialog потребуется специальное оформление. Далее определяются размеры окон и они
выводятся на экран.
Следует обратить внимание на метод корневой панели setWindowDecorationStyle(), позволяющий
настроить оформление окна. Если окно с рамкой имеет только один тип оформления, то
диалоговые окна в зависимости от их цели (представление информации, сообщение об ошибке и т.д.)
могут выглядеть по-разному. В примере было определено, что создаваемое диалоговое окно требуется
для вывода информации и должно выглядеть соответствующим образом.
Интерфейс примера окон, оформленных с внешним видом Metal, представлен на следующем
скриншоте.
Специальное оформление окон может быть полезно как средство, позволяющее полностью, вплоть
до окон, управлять внешним видом вашего приложения. Создав собственного UI-представителя
корневой панели, можно придать своему приложению уникальный вид, легко узнаваемый
пользователями.
Скачать примеры
Исходные коды примеров, рассмотренных в тексте страницы, можно
скачать здесь (3.54 Кб).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
import javax.swing.JFrame; import javax.swing.WindowConstants; import java.awt.*; import java.awt.geom.Point2D; import java.awt.geom.GeneralPath; import java.awt.Graphics2D; import javax.swing.JPanel; public class Frame { public static void main(String[] args) { JFrame frame = new JFrame(); DrawPanel panel = new DrawPanel(); frame.add(panel); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); frame.setSize(800, 600); frame.setVisible(true); } } public class Plane implements DrawableObject { private int xpoint[] = {530,465,465,200,200,465,465,315,365,490, 570,695,745,595,595,860,860,595,595}; private int ypoint[] = {50,140,290,490,560,520,560,670,740, 675,675,740,670,560,520,560,490,290,140}; @Override public void draw(Graphics2D g2d){ Point2D start = new Point2D.Float(0, 0); Point2D end = new Point2D.Float(800, 800); float[] dist = {0.2f, 1.0f}; Color[] colors = {Color.BLUE, Color.GREEN}; LinearGradientPaint bluetogreen = new LinearGradientPaint(start, end, dist, colors); g2d.setPaint(bluetogreen); g2d.fillPolygon(xpoint,ypoint,19); } } public interface DrawableObject { void draw(Graphics2D g2d); } public class DrawPanel extends JPanel { @Override public void paint(Graphics gr) { Graphics2D g2d = (Graphics2D) gr; Plane plane = new Plane(); plane.draw(g2d); Star star = new Star(230, 490); Star star2 = new Star(790, 490); star.draw(g2d); star2.draw(g2d); gr.setColor(Color.BLACK); gr.setFont(new Font("Calibri", Font.BOLD,70)); gr.drawString("И-16",465,500); } } public class Star implements DrawableObject { private int x, y; public Star(int x, int y) { this.x = x; this.y = y; } @Override public void draw(Graphics2D g2d) { int xPoints[]= {18, 30, 0, 36, 6}; int yPoints[]= {0, 36, 12, 12, 36}; GeneralPath star = new GeneralPath(); star.moveTo(xPoints[0]+ x, yPoints[0]+ y); for (int i = 1; i < xPoints.length; i++) { star.lineTo(xPoints[i]+ x, yPoints[i]+ y); } star.closePath(); g2d.setColor(Color.RED); g2d.fill(star); } } |
В стандарт Java входит два пакета для создания оконного пользовательского интерфейса: awt и его надстройка swing. Компоненты swing имеют расширенные возможности по сравнению с аналогичными awt компонентами, поэтому упор будет сделан на них. Во-вторых, в отличие от awt компоненты swing не содержат платформо-зависимого кода. Так сказать являются облегченными (lightweight) компонентами.
контейнеры верхнего уровня
- JApplet — главное окно апплета;
- JFrame — окно приложения;
- JDialog — диалог приложения.
- JColorChooser — диалог выбора цвета;
- JFileChooser — диалог выбора файлов и директорий;
- FileDialog — диалог выбора файлов и директорий (awt компонент).
простые контейнеры
- JPanel — простая панель для группировки элементов, включая вложенные панели;
- JToolBar — панель инструментов (обычно это кнопки);
- JScroolPane — панель прокрутки, позволяющая прокручивать содержимое дочернего элемента;
- JDesktopPane — контейнер для создания виртуального рабочего стола или приложений на основе MDI (multiple-document interface);
- JEditorPane, JTextPane — контейнеры для отображения сложного документа как HTML или RTF;
- JTabbedPane — контейнер для управления закладками;
- JSplitPane — контейнер, разделяющий два элемента и позволяющий пользователю изменять их размер.
элементы интерфейса
Следующие элементы управления могут использоваться и как контейнеры, так как наследуются от класса java.awt.Container.
- JButton — кнопка;
- JCheckBox — кнопка-флажок;
- JComboBox — выпадающий список;
- JLabel — метка, надпись;
- JList — список;
- JPasswordField — текстовое поле для скрытого ввода;
- JProgressBar — компонент для отображения числа в некотором диапазоне;
- JRadioButton — преключатели, радио-кнопки, обычно используется с
компонентом ButtonGroup; - JSlider — компонент позволяющий выбрать значение из заданного диапазона;
- JSpinner — компонент позволяющий выбрать значение из указанной последовательности;
- JTable — таблица;
- JTextField — однострочное текстовое поле;
- JTextArea — многострочное текстовое поле;
- JTree — дерево.
управление позиционированием и размерами
Для автоматического позиционирования и задания размеров дочерних элементов контейнерыиспользуют специальные объекты — компоновщики. Для ручного позиционирования надо установить пустой объект вызовом метода setLayout(null).
Ниже приведен список стандартных компоновщиков:
- BorderLayout — размещает элементы в один из пяти регионов, как было указано при добавлении элемента в контейнер:
наверх, вниз, влево, вправо, в центр; - FlowLayout — размещает элементы по порядку в том же направлении, что и ориентация контейнера (слева на право по умолчанию)
применяя один из пяти видов выравнивания, указанного при создании менеджера.
Данный менеджер используется по умолчанию в большинстве контейнерах; - GridLayout — размещает элементы таблично. Колличество столбцов и строк указывается
при создании менеджера. По умолчанию одна строка, а число столбцов равно числу элементов; - BoxLayout — размещает элементы по вертикали или по горизонтали. Обычно он используется не
напрямую а через контейнерный класс Box, который имеет дополнительные возможности; - SpringLayout — это менеджер низкого уровня и был разработан для программ
построителей форм; - GroupLayout — данный менеджер также был разработан для построителей форм.
события
Элементы интерфейса и контейнеры генерируют ряд событий, например:
- ActionEvent — событие, определяемое компонентом, например нажатие кнопки;
- ComponentEvent — генерируется, когда позиция, размер или видимость компонента изменяются;
- ContainerEvent — генерируется при добавлении или удалении элемента из контейнера;
- FocusEvent — генерируется при получении или потери фокуса ввода компонентом;
- ItemEvent — событие выбора или отменены выбора элемента.
Например, изменение состояния кнопки-флажка, выбор элемента меню или списка; - KeyEvent — событие ввода с клавиатуры;
- MouseEvent — события мыши;
- WindowEvent — события окна, как активация и свертывание.
Для обработки событий элемента в нем необходимо зарегистрировать объект обработчик
в числе слушателей. Делается это методами типа addxxxListener, например addMouseListener(). В качестве объектов обработчиков обычно выбирают контейнер, в котором содержится элемент.Обработка события осуществляется через соответствующий интерфейс, например:
- ActionListener — интерфейс обработки события ActionEvent;
- ItemListener — интерфейс обработки события ItemEvent;
- KeyListener — интерфейс обработки события KeyEvent;
- MouseListener — интерфейс обработки события MouseEvent, для нажатия/отжатия кнопок и входа/ухода курсора мыши с
области компонента; - MouseMotionListener — интерфейс обработки события MouseEvent, для движение курсора мыши или перетаскивании мышью;
- MouseWheelListener — интерфейс обработки события MouseEvent, для прокрутки
колеса мыши.
Если весь интерфейс реализовывать не нужно, например, нужен только
один из методов, то можно воспользоваться адаптерами.
Первое оконное приложение с использованием Java Swing
Обычно оконное приложение состоит из одного и более окон и диалогов.
В отличие от простых контейнеров контейнеры верхнего уровня имеют более сложную внутреннюю структуру. Для них автоматически создается корневой контейнер — объект класса JRootPane, который можно получить методом getRootPane(). Внутри корневого создаются еще дваобъекта: слойный контейнер и объект представляющий окно как компонент.
В большинстве случаев в слойном контейнере используются первых два контейнера слоя. Первый для хранения большинства элементов управления окна, так сказать клиентская область окна. Для доступа к нему прямо из окна используется метод getContentPane, также его можно заменить любым другим контейнером методом setContentPane(). Второй контейнер слой используется для хранения меню, панелей инструментов и т.п. Например, панель меню, добавляемая к окну, методом setJMenuBar() сохраняется именно там.
Методом getGlassPane можно получить объект представляющий окно как компонент для обработки событий или рисования поверх всех других компонент.
Ниже приведен минимальный шаблон оконного приложения.
Классы MyPanel и MyComponent — пользовательские классы, которые будут реализованы в некоторыхследующих примерах для демонстрации возможностей swing. Вам остается просто скопировать со страницы код MyPanel/MyComponent в проект со шаблоном, подправить шаблон и запустить его.
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import javax.swing.JFrame;
/**
* @author DarkRaha
*
*/
public class MyWin extends JFrame {
// серийный номер класса
private static final long serialVersionUID = 1L;
public MyWin() {
Container c = getContentPane(); // клиентская область окна
c.setLayout(new BorderLayout()); // выбираем компоновщик
// добавляем какие-нибудь дочерние элементы
//MyComponent child = new MyComponent();
MyPanel child= new MyPanel();
c.add(child);
// -------------------------------------------
// настройка окна
setTitle("Example window"); // заголовок окна
// желательные размеры окна
setPreferredSize(new Dimension(640, 480));
// завершить приложение при закрытии окна
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack(); // устанавливаем желательные размеры
setVisible(true); // отображаем окно
}
// запуск оконного приложения
public static void main(String args[]) {
new MyWin();
}
}
Ниже приведен более сложный пример с несколькими дочерними элементами и обработкой
событий.
// пример оконного приложения
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
/**
* @author DarkRaha
*
*/
public class MainWin extends JFrame implements ActionListener {
// версия класса
private static final long serialVersionUID = 1L;
// некоторые элементы окна
private JTextArea jta = new JTextArea(
"Scroll bar will appear, when much text");
public MainWin() {
// ------------------------------------------
// добавление и настройка компонент
Container c = getContentPane(); // клиентская область окна
c.setLayout(new BorderLayout()); // выбираем компоновщик
// метку наверх
c.add(new JLabel("my first label :)"), BorderLayout.NORTH);
// две кнопки в дополнительную панель
JPanel jp = new JPanel();
JButton jbt = new JButton("Add text");
jbt.addActionListener(this); // назначаем обработчик события
jp.add(jbt);
jbt = new JButton("Clear text");
jbt.addActionListener(this); // назначаем обработчик события
jp.add(jbt);
// добавляем панель вниз
c.add(jp, BorderLayout.SOUTH);
// помещаем текст. поле в область прокрутки
// а область прокрутки в центр окна,
// BorderLayout.CENTER значение по умолчанию
c.add(new JScrollPane(jta));
jta.setLineWrap(true); // автоматический перенос строк
// всплывающая подсказка
jta.setToolTipText("this is simple text editor");
// -------------------------------------------
// настройка окна
...
}
// обработчик события, метод интерфейса ActionListener
public void actionPerformed(ActionEvent arg0) {
if (arg0.getActionCommand().equals("Add text"))
jta.append(" Add text\n");
if (arg0.getActionCommand().equals("Clear text"))
jta.setText("");
// если ссылки на объекты сохранены можно сравнивать
// по объектам, например для JButton jbOK= new JBUtton("Ok");
// то сравнение будет таким
// if(arg0.getSource().equals(jbOK))
}
// запуск оконного приложения
public static void main(String args[]) {
new MainWin();
}
}
Компоновщики
Менеджеры компоновки используются для автоматического позиционирования и задания размеров дочерних элементов в контейнере. Компоновщиком является любой объект реализующий интерфейс LayoutManager или LayoutManager2 (поддерживает выравнивание и ограничения).
стандартные компоновщики
- BorderLayout — размещает элементы в один из пяти регионов, как было указано при добавлении элемента в контейнер: наверх, вниз, влево, вправо, в центр. По умолчанию элемент добавляется в центр. Если в указанном регионе уже есть элемент, то он замещается новым. Поэтому, когда надо разместить несколько элементов в одном регионе, то их объединяют в один контейнер (обычно JPanel);
- FlowLayout — размещает элементы по порядку в том же направлении, что
и ориентация контейнера (слева на право по умолчанию)
применяя один из пяти видов выравнивания, указанного при создании менеджера.
Данный менеджер используется по умолчанию; - GridLayout — размещает элементы таблично. Колличество столбцов и строк указывается при создании менеджера. По умолчанию одна строка, а число столбцов равно числу элементов. Вся область контейнера разбивается на ячейки и размер каждого элемента устанавливается в размерячейки. Это больше подходит для выравнивания панелей и других контейнеров, а не элементов управления (нам ведь не нужны гигантские кнопки);
- BoxLayout — размещает элементы по вертикали или по горизонтали.
Обычно он используется не напрямую, а через контейнерный класс Box (ящик).
точное позиционирование и задание размеров
Если в контейнере отсутствует компоновщик (был вызван метод контейнера setLayout(null)), то позицию и размеры элементов необходимо задать явно методами элемента
- setLocation(Point p) — переместить компонент в указанную точку;
- setLocation(int x, int y) — переместить компонент в указанную точку;
- setSize(Dimension d) — установить размеры компонента;
- setSize(int width, int height) — установить размеры компонента;
- setBounds(Rectangle r) — переместить и установить размеры компонента
(вписать в четырехугольник); - setBounds(int x,int y, int width, int height) — переместить и установить
размеры компонента.
предпочтительные размеры
Компоненты обладают минимальными, максимальными и предпочтительными размерами.
Некоторые компоновщики используют эти параметры, а значит можно повлиять на их работу, изменяя их. Эти размеры также могут пригодится при разработке собственного компоновщика. Если все размеры компонента равны, то говорят, что у компонента фиксированный размер. Получить и установить эти значения можно методами:
- getMaximumSize() — получение максимального размера;
- setMaximumSize(Dimension d) — установка максимального размера;
- getMinimumSize() — получение минимального размера;
- setMinimumSize(Dimension d) — установка минимального размера;
- getPreferredSize() — получение желательного размера;
- setPreferredSize(Dimension d) — установка желательного размера.
компоновщики низкого уровня
Существует также два компоновщика низкого уровня, разработанных для программ построителей форм SpringLayout и GroupLayout. В
документации
для SpringLayout можно скачать файлик SpringUtilities.java, где реализованы два полезных способа компоновки на его основе (как там сказано просто вызываем методы из этого файла, не вникая в детали:).
класс Box
Класс Box реализует контейнер с компоновщиком BoxLayout. Если элементы размещаются по горизонтали, то высота всех элементов равна высоте самого высокого элемента.А ширина элементов такова, чтобы заполнить весь контейнер по ширине.
При изменении ширины контейнера элементы растягиваются пропорционально. Если у всех элементов достигнут предел растяжения (значение getMaximumSize()), то первый элемент растягивается насильно. Если остается хотя бы один элемент доступный для растяжения, то растягивается только он.
Подобным образом происходит и вертикальное размещение. Ширина всех элементов равна ширине самого широкого элемента, а высота элеметов такова, чтобы заполнить весь контейнер по высоте. При этом может понадобится явное задание выравнивания элементов методом setAlignmentX. Иначе даже при одинаковой ширине, элементы не будут выстроены в красивый столбик.
Класс Box имеет статические методы для создания невидимых элементов для различных целей:
- createHorizontalStrut(int width) — создает компонент с фиксированной шириной. При горизонтальной укладке элемент используется чтобы освободить пространство между соседними элементами, иначе элементы будут впритык. При вертикальной укладке элемент используется для задания минимальной ширины остальных элементов;
- createVerticalStrut(int height) — создает компонент с фиксированной высотой. При вертикальной укладке элемент используется чтобы освободить пространство между соседними элементами, иначе элементы будут впритык. При горизонтальной укладке элемент используется для задания минимальной высоты остальных элементов;
- createRigidArea(Dimension d) — создает невидимый элемент фиксированного размера;
- createGlue() — создает невидимый растягиваемый компонент. Используется, чтобы предотвратить насильное растяжение элементов. Например, пусть в контейнере видимые элементы фиксированного размера. Тогда положив данный компонент в начало и в конец контейнера, мы получим центрирование видимых элементов. А если расположить его после каждого видимого, то при увеличении размера контейнера, видимые элементы «разойдутся» друг от друга.
пример использования компоновщиков
Ниже приведен пример использования некоторых компоновщиков. Цветные бордюры служат для разграничения текстовых полей друг от друга, если вызовы метода createVerticalStrut буду закомментированы.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class MyPanel extends JPanel {
private static final long serialVersionUID = 1L;
private String items[] = new String[] { "item1", "item2",
"item3", "item4", "item5" };
public MyPanel() {
setLayout(new BorderLayout()); // выбираем компоновщик
// сеточная растановка в два столбца
// много строк
JPanel jp = new JPanel();
jp.setLayout(new GridLayout(0, 2));
JButton jb;
JComboBox cb = new JComboBox(items);
jp.add(cb);
jb = new JButton("bt1");
jp.add(jb);
jb = new JButton("bt2");
jp.add(jb);
jb = new JButton("bt3");
jp.add(jb);
jb = new JButton("bt4");
jp.add(jb);
// укладываем элементы в ящик
Box bv = new Box(BoxLayout.Y_AXIS);
// минимальная ширина текстовых полей
bv.add(Box.createHorizontalStrut(60));
JTextArea jta = new JTextArea();
// рамка вокруг текстового поля
jta.setBorder(BorderFactory.createLineBorder(Color.green));
bv.add(jta);
// пустое место в 15 пикселей
bv.add(Box.createVerticalStrut(15));
// для эксперемента с размерами
// jta.setPreferredSize(new Dimension(60,100));
// jta.setMaximumSize(new Dimension(60,100));
// jta.setAlignmentX(LEFT_ALIGNMENT); // явно задаем выравнивание
jta = new JTextArea();
jta.setBorder(BorderFactory.createLineBorder(Color.green));
bv.add(jta);
bv.add(Box.createVerticalStrut(15));
jta = new JTextArea();
jta.setBorder(BorderFactory.createLineBorder(Color.green));
bv.add(jta);
bv.add(Box.createVerticalStrut(15));
add(jp); // добавляем панель в центр
add(bv, BorderLayout.WEST); // добавляем ящик влево
}
}




