Swing: изменение размера JFrame как фреймов в Linux e.g
Я хотел бы знать, есть ли возможность реализовать изменение размера JFrame таким образом, что он был изменен, как, например, стандартные окна в linux. Точнее: если пользователь начнет перетаскивать, только будущий размер, если окно будет предварительно просмотрено, а исходное содержимое не будет изменено. Как только пользователь отпускает мышь, кадр изменяется до этого размера. В изображениях:
(1) состояние до изменение размера
(2) пользователь начинает перетаскивать (на красный круг)
(3) пользователь отпускает мышь, кадр получает изменение размера
можно ли понять, что в Java Swing?
EDIT:
поскольку эта программа Однажды должна работать также в нижней Java RE Как 7, я попытался объединить предложения mKorbel С и предложение в комментарии с фреймом translucend. Результат близок к цели, за исключением того, что
- содержимое contentPane изменяется после того, как я перестаю перемещать мышь, а не когда мышь освобождается
- заголовок кадра сразу изменяется, не только whend я остановить перетаскивание границы кадра.
- он работает только при изменении размера справа или снизу, в противном случае содержимое перемещается с перетаскиванием.
Я думаю, что первый пункт разрешима комбинацией кода и MouseListener, что-то вроде if mouseReleased(), затем resize . Вот код, не стесняйтесь попробовать. Для дальнейших предложений я все еще рад любым предложениям.
код является незначительной модификацией GradientTranslucentWindowDemo.java из учебников Java. Я надеюсь, что это разрешено размещать его здесь, иначе, пожалуйста, укажите мне любое нарушение авторских причин. Черный JPanel должен быть содержание приложения, где как contentPane остается невидимым.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import static java.awt.GraphicsDevice.WindowTranslucency.*;
public class GroundFrame extends JFrame {
Timer timer;
JPanel panel2;
public GroundFrame() {
super("GradientTranslucentWindow");
setBackground(new Color(0,0,0,0));
setSize(new Dimension(300,200));
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel() {
panel.setBackground(new Color(0,0,0,0));
setContentPane(panel);
setLayout(null);
panel2 = new JPanel();
panel2.setBackground(Color.black);
panel2.setBounds(0,0,getContentPane().getWidth(), getContentPane().getHeight());
getContentPane().add(panel2);
addComponentListener(new ComponentListener() {
@Override
public void componentShown(ComponentEvent e) {}
@Override
public void componentResized(ComponentEvent e) {
timer = new Timer(50, new Action() {
@Override
public void actionPerformed(ActionEvent e) {
if(timer.isRunning()){
}else{
resizePanel(getContentPane().getSize());
}
}
@Override
public void setEnabled(boolean b) {}
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {}
@Override
public void putValue(String key, Object value) {}
@Override
public boolean isEnabled() {return false;}
@Override
public Object getValue(String key) {return null;}
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {}
});
timer.setRepeats(false);
timer.start();
}
@Override
public void componentMoved(ComponentEvent e) {}
@Override
public void componentHidden(ComponentEvent e) {}
});
}
public void resizePanel(Dimension dim){
panel2.setBounds(0,0,dim.width, dim.height);
repaint();
}
public static void main(String[] args) {
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
boolean isPerPixelTranslucencySupported =
gd.isWindowTranslucencySupported(PERPIXEL_TRANSLUCENT);
if (!isPerPixelTranslucencySupported) {
System.out.println(
"Per-pixel translucency is not supported");
System.exit(0);
}
JFrame.setDefaultLookAndFeelDecorated(true);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
GroundFrame gtw = new GroundFrame();
gtw.setVisible(true);
}
});
}
}
3 ответов
+1 к ответам мкорбеля и Дениса Тульского.
я сделал своего рода абстрактное решение, которое может помочь. Он поддерживает изменение размера (увеличение и уменьшение высоты и ширины)JFrame
со всех четырех сторон JFrame
(север, восток, юг и Запад) он также может быть изменен по ширине и высоте одновременно, когда мышь перемещается в один из углов.
в основном то, что я сделал:
- добавить
MouseMotionListener
иMouseListener
дляJFrame
- переопределить
mouseDragged(..)
,mouseMoved(..)
,mousePressed(..)
иmouseReleased(..)
ofListener
s. - set
JFrame
не изменять. - на
mouseMoved(..)
слушайте, когда мышь значение 10px или меньше снизу или справа. изJFrame
, затем он устанавливает соответствующее направление изменения размера (высота или ширина), изменяет мышьCursor
(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)
для крайнего правого / изменения ширины,Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)
для нижнего/hieght изменения размера,Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR)
для верхней части высоты рамки изменяя размер илиCursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR)
для изменения ширины левой стороны) соответственно и вызовитеcanResize(true)
. - на
mouseDragged(..)
обновить ширину или высоту для нового размера, как его перетащили в направлении - на
mouseReleased(..)
установитьJFrame
к новому размеру. - на
mousePressed(..)
мы проверяем для потребителя отжатые координаты (это позволяет нам увидеть если размер рамки уменьшает/увеличивает).
проверьте этот пример I сделано:
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class JFrameSizeAfterDrag extends JFrame {
//direction holds the position of drag
private int w = 0, h = 0, direction, startX = 0, startY = 0;
public JFrameSizeAfterDrag() {
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
addMouseListener(new MouseAdapter() {
//so we can see if from where the user clikced is he increasing or decraesing size
@Override
public void mousePressed(MouseEvent me) {
super.mouseClicked(me);
startX = me.getX();
startY = me.getY();
System.out.println("Clicked: " + startX + "," + startY);
}
//when the mouse is relaeased set size
@Override
public void mouseReleased(MouseEvent me) {
super.mouseReleased(me);
System.out.println("Mouse released");
if (direction == 1 || direction == 2 || direction == 5 || direction == 6) {
setSize(w, h);
} else {//this should move x and y by as much as the mouse moved then use setBounds(x,y,w,h);
setBounds(getX() - (startX - me.getX()), getY() - (startY - me.getY()), w, h);
}
validate();
}
});
addMouseMotionListener(new MouseAdapter() {
private boolean canResize;
//while dragging check direction of drag
@Override
public void mouseDragged(MouseEvent me) {
super.mouseDragged(me);
System.out.println("Dragging:" + me.getX() + "," + me.getY());
if (canResize && direction == 1) {//frame height change
if (startY > me.getY()) {//decrease in height
h -= 4;
} else {//increase in height
h += 4;
}
} else if (canResize && direction == 2) {//frame width change
if (startX > me.getX()) {//decrease in width
w -= 4;
} else {//increase in width
w += 4;
}
} else if (canResize && direction == 3) {//frame height change
if (startX > me.getX()) {//decrease in width
w += 4;
} else {//increase in width
w -= 4;
}
} else if (canResize && direction == 4) {//frame width change
if (startY > me.getY()) {//decrease in height
h += 4;
} else {//increase in height
h -= 4;
}
} else if (canResize && direction == 5) {//frame width and height change bottom right
if (startY > me.getY() && startX > me.getX()) {//increase in height and width
h -= 4;
w -= 4;
} else {//decrease in height and with
h += 4;
w += 4;
}
} /* Windows dont usually support reszing from top but if you want :) uncomment code in mouseMoved(..) also
else if (canResize && direction == 6) {//frame width and height change top left
if (startY > me.getY() && startX > me.getX()) {//decrease in height and with
h += 4;
w += 4;
} else {//increase in height and width
h -= 4;
w -= 4;
}
} else if (canResize && direction == 8) {//frame width and height change top right
if (startY > me.getY() && startX > me.getX()) {//increase in height and width
h -= 4;
w -= 4;
} else {//decrease in height and with
h += 4;
w += 4;
}
}
*/ else if (canResize && direction == 7) {//frame width and height change bottom left
if (startY > me.getY() && startX > me.getX()) {//increase in height and width
h -= 4;
w -= 4;
} else {//decrease in height and with
h += 4;
w += 4;
}
}
}
@Override
public void mouseMoved(MouseEvent me) {
super.mouseMoved(me);
if (me.getY() >= getHeight() - 10 && me.getX() >= getWidth() - 10) {//close to bottom and right side of frame show south east cursor and allow height witdh simaltneous increase/decrease
//System.out.println("resize allowed..");
canResize = true;
setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
direction = 5;
} /*Windows dont usually support reszing from top but if you want :) uncomment code in mouseDragged(..) too
else if (me.getY() <= 28 && me.getX() <= 28) {//close to top side and left side of frame show north west cursor and only allow increase/decrease in width and height simultaneosly
//System.out.println("resize allowed..");
canResize = true;
setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR));
direction = 6;
} else if (me.getY() <= 28 && me.getX() >= getWidth() - 10) {//close to top and right side of frame show north east cursor and only allow increase/decrease in width and height simultaneosly
//System.out.println("resize allowed..");
canResize = true;
setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR));
direction = 8;
}
*/ else if (me.getY() >= getHeight() - 10 && me.getX() <= 10) {//close to bottom side and left side of frame show north west cursor and only allow increase/decrease in width and height simultaneosly
//System.out.println("resize allowed..");
canResize = true;
setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR));
direction = 7;
} else if (me.getY() >= getHeight() - 10) {//close to bottom of frame show south resize cursor and only allow increase height
//System.out.println("resize allowed");
canResize = true;
setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
direction = 1;
} else if (me.getX() >= getWidth() - 10) {//close to right side of frame show east cursor and only allow increase width
//System.out.println("resize allowed");
canResize = true;
setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
direction = 2;
} else if (me.getX() <= 10) {//close to left side of frame show east cursor and only allow increase width
//System.out.println("resize allowed");
canResize = true;
setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
direction = 3;
} else if (me.getY() <= 28) {//close to top side of frame show east cursor and only allow increase height
// System.out.println("resize allowed..");
canResize = true;
setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
direction = 4;
} else {
canResize = false;
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
// System.out.println("resize not allowed");
}
}
});
//just so GUI is visible and not small
add(new JPanel() {
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
});
pack();
setVisible(true);
}
@Override
public void setVisible(boolean bln) {
super.setVisible(bln);
w = getWidth();
h = getHeight();
}
public static void main(String[] args) {
/**
* Create GUI and components on Event-Dispatch-Thread
*/
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new JFrameSizeAfterDrag();
}
});
}
}
обновление:
отличный пример, который вы сделали, я исправил код, добавив MouseAdapter
, который переопределяет mouseReleased(..)
которых звонки resizePanel(...)
, когда mouseReleased(..)
см. здесь для фиксированного кода (также исправлено несколько незначительных вещей, таких как added ComponentAdapter
вместо ComponentListener
и AbstractAction
вместо Action
):
import java.awt.*;
import static java.awt.GraphicsDevice.WindowTranslucency.*;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class JFrameSizeAfterDrag2 extends JFrame {
private Timer timer;
private JPanel panel2;
boolean canResize = true,firstTime = true;
public JFrameSizeAfterDrag2() {
super("GradientTranslucentWindow");
setBackground(new Color(0, 0, 0, 0));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setContentPane(new JPanel(null) {//contentpane layout is null only
@Override
protected void paintComponent(Graphics g) {
Paint p = new GradientPaint(0.0f, 0.0f, new Color(0, 0, 0, 0), 0.0f, getHeight(), new Color(0, 0, 0, 0), true);
Graphics2D g2d = (Graphics2D) g;
g2d.setPaint(p);
g2d.fillRect(0, 0, getWidth(), getHeight());
}
@Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
});
panel2 = new JPanel();
panel2.setBackground(Color.black);
getContentPane().add(panel2);
addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent me) {
super.mouseReleased(me);
if (canResize) {
resizePanel(getContentPane().getSize());
}
}
});
addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
timer = new Timer(50, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
if (timer.isRunning()) {
canResize = false;
} else {
canResize = true;
if (firstTime == true) {
firstTime = false;
resizePanel(getContentPane().getSize());
}
}
}
});
timer.setRepeats(false);
timer.start();
}
});
pack();
}
public void resizePanel(Dimension dim) {
panel2.setBounds(0, 0, dim.width, dim.height);
revalidate();
}
public static void main(String[] args) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gd = ge.getDefaultScreenDevice();
boolean isPerPixelTranslucencySupported = gd.isWindowTranslucencySupported(PERPIXEL_TRANSLUCENT);
if (!isPerPixelTranslucencySupported) {
System.out.println("Per-pixel translucency is not supported");
System.exit(0);
}
JFrame.setDefaultLookAndFeelDecorated(true);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrameSizeAfterDrag2 gtw = new JFrameSizeAfterDrag2();
gtw.setVisible(true);
}
});
}
}
только будущий размер, если окно будет просмотрено, в то время как исходный контент не изменяется. Как только пользователь отпускает мышь, кадр изменяется до этого размера
очень сложная идея, но
добавить
ComponentListener
доJFrame
переопределить componentResized (ComponentEvent e)
добавить Качели Таймер С небольшой задержкой (400-600) с выходом на Качели
если изменение размера продолжается, то вызовите
Timer#restart()
редактировать
используйте этот код для тестирования
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
public class ComponentEventDemo extends JPanel
implements ComponentListener, HierarchyListener,
ItemListener {
private JFrame frame;
private static final long serialVersionUID = 1L;
private JTextArea display;
private JLabel label;
private JComboBox comboBox;
private JComboBox comboBox1;
private String newline = "\n";
private Vector<String> listSomeString = new Vector<String>();
private Vector<String> listSomeAnotherString = new Vector<String>();
public ComponentEventDemo() {
listSomeString.add("-");
listSomeString.add("Snowboarding");
listSomeString.add("Rowing");
listSomeString.add("Knitting");
listSomeString.add("Speed reading");
listSomeString.add("Pool");
listSomeString.add("None of the above");
//
listSomeAnotherString.add("-");
listSomeAnotherString.add("XxxZxx Snowboarding");
listSomeAnotherString.add("AaaBbb Rowing");
listSomeAnotherString.add("CccDdd Knitting");
listSomeAnotherString.add("Eee Fff Speed reading");
listSomeAnotherString.add("Eee Fff Pool");
listSomeAnotherString.add("Eee Fff None of the above");
comboBox = new JComboBox(listSomeString);
comboBox1 = new JComboBox(listSomeAnotherString);
display = new JTextArea();
display.setEditable(false);
JScrollPane scrollPane = new JScrollPane(display);
scrollPane.setPreferredSize(new Dimension(350, 200));
label = new JLabel("This is a label", JLabel.CENTER);
label.addComponentListener(this);
JCheckBox checkbox = new JCheckBox("Label visible", true);
checkbox.addItemListener(this);
checkbox.addComponentListener(this);
JPanel panel = new JPanel(new GridLayout(1, 2));
panel.add(label);
panel.add(checkbox);
panel.addComponentListener(this);
frame = new JFrame("ComponentEventDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane, BorderLayout.CENTER);
frame.add(panel, BorderLayout.PAGE_END);
frame.pack();
frame.setVisible(true);
}
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
label.setVisible(true);
label.revalidate();
label.repaint();
} else {
label.setVisible(false);
}
}
protected void displayMessage(String message) {
//If the text area is not yet realized, and
//we tell it to draw text, it could cause
//a text/AWT tree deadlock. Our solution is
//to ensure that the text area is realized
//before attempting to draw text.
// if (display.isShowing()) {
display.append(message + newline);
display.setCaretPosition(display.getDocument().getLength());
//}
}
public void componentHidden(ComponentEvent e) {
displayMessage(e.getComponent().getClass().getName() + " --- Hidden");
}
public void componentMoved(ComponentEvent e) {
displayMessage(e.getComponent().getClass().getName() + " --- Moved");
}
public void componentResized(ComponentEvent e) {
displayMessage(e.getComponent().getClass().getName() + " --- Resized ");
}
public void componentShown(ComponentEvent e) {
displayMessage(e.getComponent().getClass().getName() + " --- Shown");
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
ComponentEventDemo componentEventDemo = new ComponentEventDemo();
}
});
}
public void hierarchyChanged(HierarchyEvent e) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
простой трюк, чтобы имитировать такое поведение, чтобы сделать кадр без изменения размера и посвятить некоторую часть кадра, чтобы быть ручки изменения размера, а затем добавить прослушиватели мыши и изменить его самостоятельно:
public static class GroundFrame extends JFrame {
private boolean doResize = false;
public GroundFrame() throws HeadlessException {
setResizable(false);
getContentPane().addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
Point point = e.getPoint();
if (point.x >= getWidth() - 50) {
doResize = true;
}
}
@Override
public void mouseDragged(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
if (doResize) {
setSize(e.getX(), getHeight());
doResize = false;
}
}
});
}
}
вы даже можете сделать jframe undecorated и выполнить все операции, такие как изменение размера, перемещение, закрытие и т. д. себе.
но опять же, это поведение контролируется оконным менеджером или композитным менеджером (вы можете настроить compiz, чтобы сделать это для вас, для образец.) Я думаю, что live-resizing был одной из ключевых рекламируемых функций NeXT, крупным шагом вперед в то время :)
кроме того, еще один трюк, который я пробовал, основан на том, что java 7 сообщает об изменении размера событий, как они происходят, а не на выпуске мыши, поэтому можно сохранить размер окна после первого изменения размера, а затем восстановить его, пока изменение размера не будет завершено. Работает не очень гладко, хотя:
public static class GroundFrame extends JFrame {
private Timer timer;
private Dimension oldSize;
public GroundFrame() throws HeadlessException {
timer = new Timer(500, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
oldSize = null;
invalidate();
}
});
timer.setRepeats(false);
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
if (oldSize == null) {
oldSize = getSize();
timer.start();
} else {
setSize(oldSize);
timer.restart();
}
}
});
}
}