I'm looking at this example Using Swing Components; Examples. This example shows JTabbedPane with custom tab component which has close button in each tab.
If JTabbedPane is in WRAP_TAB_LAYOUT the tab title and the close button is in the middle of the wide tab. How to change this example that the tab title still would be visible in the center of the tab, but the close button would appear next to right tab border?
Here is a picture:
Here is one possible implementation using UIManager.put("TabbedPane.tabInsets", insets) and JLayer
Paint a close button on the inner margin of the tab using the JLayer
I didn't test on NumbusLookAndFeel
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.plaf.*;
public class RightCloseTabButtonTest {
public JComponent makeUI() {
JTabbedPane tabs = new JTabbedPane();
tabs.addTab("Tab 1", new JLabel("aaa"));
tabs.addTab("Tab 2", new JLabel("bbb"));
tabs.addTab("Tab 3", new JLabel("ccc"));
tabs.addTab("Tab 4", new JLabel("ddd"));
return new JLayer<JTabbedPane>(tabs, new CloseableTabbedPaneLayerUI());
}
public static void main(String... args) {
EventQueue.invokeLater(() -> {
UIManager.put("TabbedPane.tabInsets", new Insets(2, 2 + 16, 2, 2 + 16));
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new RightCloseTabButtonTest().makeUI());
f.setSize(300, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
class CloseTabIcon implements Icon {
#Override public void paintIcon(Component c, Graphics g, int x, int y) {
Graphics2D g2 = (Graphics2D) g.create();
g2.translate(x, y);
g2.setPaint(Color.BLACK);
if (c instanceof AbstractButton) {
ButtonModel m = ((AbstractButton) c).getModel();
if (m.isRollover()) {
g2.setPaint(Color.ORANGE);
}
}
g2.drawLine(4, 4, 11, 11);
g2.drawLine(4, 5, 10, 11);
g2.drawLine(5, 4, 11, 10);
g2.drawLine(11, 4, 4, 11);
g2.drawLine(11, 5, 5, 11);
g2.drawLine(10, 4, 4, 10);
g2.dispose();
}
#Override public int getIconWidth() {
return 16;
}
#Override public int getIconHeight() {
return 16;
}
}
class CloseableTabbedPaneLayerUI extends LayerUI<JTabbedPane> {
private final JComponent rubberStamp = new JPanel();
private final Point pt = new Point();
private final JButton button = new JButton(new CloseTabIcon()) {
#Override public void updateUI() {
super.updateUI();
setBorder(BorderFactory.createEmptyBorder());
setFocusPainted(false);
setBorderPainted(false);
setContentAreaFilled(false);
setRolloverEnabled(false);
}
};
#Override public void paint(Graphics g, JComponent c) {
super.paint(g, c);
if (c instanceof JLayer) {
JLayer jlayer = (JLayer) c;
JTabbedPane tabPane = (JTabbedPane) jlayer.getView();
Dimension d = button.getPreferredSize();
for (int i = 0; i < tabPane.getTabCount(); i++) {
Rectangle rect = tabPane.getBoundsAt(i);
int x = rect.x + rect.width - d.width - 2;
int y = rect.y + (rect.height - d.height) / 2;
Rectangle r = new Rectangle(x, y, d.width, d.height);
button.getModel().setRollover(r.contains(pt));
SwingUtilities.paintComponent(g, button, rubberStamp, r);
}
}
}
#Override public void installUI(JComponent c) {
super.installUI(c);
if (c instanceof JLayer) {
((JLayer) c).setLayerEventMask(
AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
}
#Override public void uninstallUI(JComponent c) {
if (c instanceof JLayer) {
((JLayer) c).setLayerEventMask(0);
}
super.uninstallUI(c);
}
#Override protected void processMouseEvent(
MouseEvent e, JLayer<? extends JTabbedPane> l) {
if (e.getID() == MouseEvent.MOUSE_CLICKED) {
pt.setLocation(e.getPoint());
JTabbedPane tabbedPane = (JTabbedPane) l.getView();
int index = tabbedPane.indexAtLocation(pt.x, pt.y);
if (index >= 0) {
Rectangle rect = tabbedPane.getBoundsAt(index);
Dimension d = button.getPreferredSize();
int x = rect.x + rect.width - d.width - 2;
int y = rect.y + (rect.height - d.height) / 2;
Rectangle r = new Rectangle(x, y, d.width, d.height);
if (r.contains(pt)) {
tabbedPane.removeTabAt(index);
}
}
}
}
#Override protected void processMouseMotionEvent(
MouseEvent e, JLayer<? extends JTabbedPane> l) {
pt.setLocation(e.getPoint());
JTabbedPane t = (JTabbedPane) l.getView();
if (t.indexAtLocation(pt.x, pt.y) >= 0) {
Point loc = e.getPoint();
loc.translate(-16, -16);
l.repaint(new Rectangle(loc, new Dimension(32, 32)));
}
}
}
Related
I am creating a rectangle with my mouse and i'm just trying to return info from the created object with a mouseover. I've been solving this with a messabox but there's just not many country to mouseover so the number of popup can be monstrous.
I decided to use a tooltip. Thing is it's not working on my mouse over :
JTextField text = new JTextField();
if (coordX > coordXRec && coordX < coordXRec + width && coordY > coordYrec && coordY < coordYrec + height){
text.setToolTipText(i.GetInfoPays());
text.getToolTipText();
}
Naturally, i want it to show when i mouseover my rectangle created :
That green rectangle was made by the user so i can't 'preset' an event
or use it as a panel for my tooltip.
This is what excepted, but using a tooltiptext, not a messabox.
I've been using a MouseEventMoved to know if im hovering over my rectangle. Its working but i'm stuck at sort of changing my messagebox into a tooltip.
Use setToolTipText("..."); with the appropriate String when needed (e.g. during paintComponent()).
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.util.*;
public class MouseShapeDetection {
private JComponent ui = null;
MouseShapeDetection() {
initUI();
}
public final void initUI() {
if (ui != null) {
return;
}
ui = new JPanel(new BorderLayout(4, 4));
ui.setBorder(new EmptyBorder(4, 4, 4, 4));
ui.add(new ShapePanel());
}
public JComponent getUI() {
return ui;
}
public static void main(String[] args) {
Runnable r = () -> {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception useDefault) {
}
MouseShapeDetection o = new MouseShapeDetection();
JFrame f = new JFrame(o.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setContentPane(o.getUI());
f.pack();
f.setMinimumSize(f.getSize());
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}
class ShapePanel extends JPanel {
Point point = new Point(0, 0);
Dimension preferredSize = new Dimension(600, 300);
ArrayList<Shape> shapes = new ArrayList<>();
Color translucent = new Color(0,0,255,87);
Color selectedColor = Color.GREEN;
Color unselectedColor = Color.RED;
public ShapePanel() {
this.addMouseMotionListener(new MotionListener());
setBackground(Color.WHITE);
Random r = new Random();
int x, y, w, h, wP = preferredSize.width, hP = preferredSize.height;
for (int ii = 0; ii < 40; ii++) {
w = r.nextInt(100)+40;
h = r.nextInt(50)+20;
x = r.nextInt(wP - w);
y = r.nextInt(hP - h);
Ellipse2D.Double ellipse = new Ellipse2D.Double(x, y, w, h);
shapes.add(ellipse);
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
StringBuilder sb = new StringBuilder("Shapes: ");
Graphics2D g2 = (Graphics2D)g;
for (int ii=0; ii<shapes.size(); ii++) {
Shape shape = shapes.get(ii);
g2.setColor(translucent);
g2.fill(shape);
if (shape.contains(point)) {
g2.setColor(selectedColor);
sb.append(ii);
sb.append(" ");
} else {
g2.setColor(unselectedColor);
}
g2.setStroke(new BasicStroke(2.5f));
g2.draw(shape);
}
setToolTipText(sb.toString());
}
#Override
public Dimension getPreferredSize() {
return preferredSize;
}
class MotionListener extends MouseMotionAdapter {
#Override
public void mouseMoved(MouseEvent e) {
point = e.getPoint();
repaint();
}
}
}
I'm trying to make a java class that contains one layeredpane with 2 JPanel and a scroller.
There are 2 drawings so that I'll be able to draw different things with different threads on each panel, however, nothing happens when I use this class, and, I've checked if I delete the layeredPane and drawingPane0, creating the scroller with drawingPane1, it works correctly...
Does anyone know whats wrong?
Thank you all!
Here it's my code:
public class ScrollPanel extends JPanel implements MouseListener{
private Dimension area; //indicates area taken up by graphics
private Vector<Rectangle> circles; //coordinates used to draw graphics
private JPanel drawingPane0;
private JPanel drawingPane1;
private JLayeredPane layeredPane;
private final Color colors[] = {
Color.red, Color.blue, Color.green, Color.orange,
Color.cyan, Color.magenta, Color.darkGray, Color.yellow};
private final int color_n = colors.length;
public ScrollPanel() {
super(new BorderLayout());
area = new Dimension(0, 0);
circles = new Vector<Rectangle>();
drawingPane1 = new DrawingPane();
layeredPane = new JLayeredPane();
drawingPane0 = new DrawingPane();
drawingPane0.setBackground(Color.WHITE);
drawingPane1.addMouseListener(this);
drawingPane1.setOpaque(false);
layeredPane.add(drawingPane0,0);
layeredPane.add(drawingPane1,1);
JScrollPane scroller = new JScrollPane(layeredPane);
add(scroller, BorderLayout.CENTER);
}
public class DrawingPane extends JPanel {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle rect;
for (int i = 0; i < circles.size(); i++) {
rect = circles.elementAt(i);
g.setColor(colors[(i % color_n)]);
g.fillOval(rect.x, rect.y, rect.width, rect.height);
}
}
}
public void mouseReleased(MouseEvent e) {
final int W = 100;
final int H = 100;
boolean changed = false;
if (SwingUtilities.isRightMouseButton(e)) {
circles.removeAllElements();
area.width = 0;
area.height = 0;
changed = true;
} else {
int x = e.getX() - W / 2;
int y = e.getY() - H / 2;
if (x < 0) {
x = 0;
}
if (y < 0) {
y = 0;
}
Rectangle rect = new Rectangle(x, y, W, H);
circles.addElement(rect);
drawingPane1.scrollRectToVisible(rect);
int this_width = (x + W + 2);
if (this_width > area.width) {
area.width = this_width;
changed = true;
}
int this_height = (y + H + 2);
if (this_height > area.height) {
area.height = this_height;
changed = true;
}
}
if (changed) {
drawingPane1.setPreferredSize(area);
drawingPane1.revalidate();
}
drawingPane1.repaint();
}
public void mouseClicked(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
}
By default, a JTable is editable and when we select any row, we get this kind of a GUI
Here we have two borders, one around the entire row, and one around the specific cell using which we have selected the row. I need the outer border (around entire row) but don't want the inner (per cell) border. Is there a way to achieve this.
I guess, you would need to make a customized Border.
import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
public class AroundEntireRowFocusTest {
String[] columnNames = {"A", "B", "C"};
Object[][] data = {
{"aaa", 12, "ddd"}, {"bbb", 5, "eee"}, {"CCC", 92, "fff"}
};
DefaultTableModel model = new DefaultTableModel(data, columnNames) {
#Override public Class<?> getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
public JComponent makeUI() {
UIManager.put("Table.focusCellHighlightBorder", new DotBorder(2, 2, 2, 2));
JTable table = new JTable(model) {
private final DotBorder dotBorder = new DotBorder(2, 2, 2, 2);
void updateBorderType(DotBorder border, boolean isLeadRow, int column) {
border.type = EnumSet.noneOf(DotBorder.Type.class);
if (isLeadRow) {
border.type.add(DotBorder.Type.LEAD);
if (column == 0) {
border.type.add(DotBorder.Type.WEST);
}
if (column == getColumnCount() - 1) {
border.type.add(DotBorder.Type.EAST);
}
}
}
#Override public Component prepareRenderer(
TableCellRenderer tcr, int row, int column) {
JComponent c = (JComponent) super.prepareRenderer(tcr, row, column);
c.setBorder(dotBorder);
updateBorderType(
dotBorder, row == getSelectionModel().getLeadSelectionIndex(), column);
return c;
}
};
table.setShowGrid(false);
table.setIntercellSpacing(new Dimension());
JPanel p = new JPanel(new BorderLayout());
p.add(new JScrollPane(table));
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new AroundEntireRowFocusTest().makeUI());
frame.setSize(320, 240);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class DotBorder extends EmptyBorder {
public enum Type { LEAD, WEST, EAST; }
public EnumSet<Type> type = EnumSet.noneOf(Type.class);
private static final BasicStroke dashed = new BasicStroke(
1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
10f, (new float[] {1f}), 0f);
private static final Color DOT_COLOR = new Color(200, 150, 150);
public DotBorder(int top, int left, int bottom, int right) {
super(top, left, bottom, right);
}
#Override public boolean isBorderOpaque() {
return true;
}
#Override public void paintBorder(
Component c, Graphics g, int x, int y, int w, int h) {
Graphics2D g2 = (Graphics2D) g.create();
g2.translate(x, y);
g2.setPaint(DOT_COLOR);
g2.setStroke(dashed);
if (type.contains(Type.WEST)) {
g2.drawLine(0, 0, 0, h);
}
if (type.contains(Type.EAST)) {
g2.drawLine(w - 1, 0, w - 1, h);
}
if (type.contains(Type.LEAD)) {
if (c.getBounds().x % 2 == 0) {
g2.drawLine(0, 0, w, 0);
g2.drawLine(0, h - 1, w, h - 1);
} else {
g2.drawLine(1, 0, w, 0);
g2.drawLine(1, h - 1, w, h - 1);
}
}
g2.dispose();
}
}
Currently, I am using the following code to drag and move my undecordated JFrames.
private void initialiseGUI(Component component){
//<editor-fold defaultstate="collapsed" desc="code">
component.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
posX = e.getX();
posY = e.getY();
}
});
component.addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent evt) {
//sets frame position when mouse dragged
Rectangle rectangle = getBounds();
getGUI().setBounds(evt.getXOnScreen() - posX, evt.getYOnScreen() - posY, rectangle.width, rectangle.height);
}
});
//</editor-fold>
}
What must I write so that the user can resize it like a decorated window, by dragging the side?
You can check out mr Rob Camick's ComponentResizer class. Pretty simple and straight forward to use.
Just instantiate the ComponentResizer and register the frame with something like:
JFrame frame = new JFrame();
ComponentResizer cr = new ComponentResizer();
cr.registerComponent(frame);
cr.setSnapSize(new Dimension(10, 10));
cr.setMaximumSize(new Dimension(...));
cr.setMinimumSize(new Dimension(...));
Here's a complete example of using the class
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.LineBorder;
public class UndecoratedExample {
private JFrame frame = new JFrame();
class MainPanel extends JPanel {
public MainPanel() {
setBackground(Color.gray);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
class BorderPanel extends JPanel {
private JLabel label;
int pX, pY;
public BorderPanel() {
label = new JLabel(" X ");
label.setOpaque(true);
label.setBackground(Color.RED);
label.setForeground(Color.WHITE);
setBackground(Color.black);
setLayout(new FlowLayout(FlowLayout.RIGHT));
add(label);
label.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
System.exit(0);
}
});
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
// Get x,y and store them
pX = me.getX();
pY = me.getY();
}
public void mouseDragged(MouseEvent me) {
frame.setLocation(frame.getLocation().x + me.getX() - pX,
frame.getLocation().y + me.getY() - pY);
}
});
addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent me) {
frame.setLocation(frame.getLocation().x + me.getX() - pX,
frame.getLocation().y + me.getY() - pY);
}
});
}
}
class OutsidePanel extends JPanel {
public OutsidePanel() {
setLayout(new BorderLayout());
add(new MainPanel(), BorderLayout.CENTER);
add(new BorderPanel(), BorderLayout.PAGE_START);
setBorder(new LineBorder(Color.BLACK, 5));
}
}
private void createAnsShowGui() {
ComponentResizer cr = new ComponentResizer();
cr.setMinimumSize(new Dimension(300, 300));
cr.setMaximumSize(new Dimension(800, 600));
cr.registerComponent(frame);
cr.setSnapSize(new Dimension(10, 10));
frame.setUndecorated(true);
frame.add(new OutsidePanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new UndecoratedExample().createAnsShowGui();
}
});
}
}
I have recently built my own prototype for this. Maybe you will find this useful.
It uses 2 different components one on top of the other. Unlike Rob Camick's ComponentResizer on which this is inspired, the mouse listeners set to the components in the JFrame will be functional. You will not get the JFrame to capture all the mouse events making it useless to attach listeners to the components in the JFrame. It captures mouse events only when and where a double headed arrow must be displayed.
The key is this method in the top component:
#Override
public boolean contains(int x, int y) {
return x < insets.left || y < insets.top
|| getHeight() - y < insets.bottom
|| getWidth() - x < insets.right;
}
Here is the code:
import java.awt.Component;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
public class BackgroundComponentDragger implements MouseMotionListener {
private Component controlledComponent;
/*
* Point where cursor was last clicked.
*/
private Point originPoint;
public BackgroundComponentDragger(Component component) {
this.controlledComponent = component;
}
#Override
public void mouseDragged(MouseEvent e) {
Point currentFramePosition = controlledComponent.getLocation();
Point newFramePosition = new Point(currentFramePosition.x + e.getX()
- originPoint.x, currentFramePosition.y + e.getY() - originPoint.y);
controlledComponent.setLocation(newFramePosition);
}
#Override
public void mouseMoved(MouseEvent e) {
originPoint = e.getPoint();
}
}
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.util.HashMap;
import java.util.Map;
public class ComponentBorderDragger implements MouseMotionListener {
private Component controlledComponent;
private byte direction;
protected static final byte NORTH = 1;
protected static final byte WEST = 2;
protected static final byte SOUTH = 4;
protected static final byte EAST = 8;
private Cursor sourceCursor;
private static Map<Byte, Integer> cursors = new HashMap<Byte, Integer>();
{
cursors.put((byte) 1, Cursor.N_RESIZE_CURSOR);
cursors.put((byte) 2, Cursor.W_RESIZE_CURSOR);
cursors.put((byte) 4, Cursor.S_RESIZE_CURSOR);
cursors.put((byte) 8, Cursor.E_RESIZE_CURSOR);
cursors.put((byte) 3, Cursor.NW_RESIZE_CURSOR);
cursors.put((byte) 9, Cursor.NE_RESIZE_CURSOR);
cursors.put((byte) 6, Cursor.SW_RESIZE_CURSOR);
cursors.put((byte) 12, Cursor.SE_RESIZE_CURSOR);
}
private Insets dragInsets;
private Dimension minSize;
private Point basePoint;
public ComponentBorderDragger(Component controlledComponent, Insets dragInsets,
Dimension minSize) {
super();
this.controlledComponent = controlledComponent;
this.dragInsets = dragInsets;
this.minSize = minSize;
}
#Override
public void mouseDragged(MouseEvent e) {
if (direction == 0) {
return;
}
Point newPoint = e.getPoint();
int x, y, width, height, newBasePointX, newBasePointY;
x = controlledComponent.getX();
y = controlledComponent.getY();
width = controlledComponent.getWidth();
height = controlledComponent.getHeight();
newBasePointX = newPoint.x;
newBasePointY = newPoint.y;
if ((direction & EAST) == EAST) {
int newWidth;
newWidth = Math.max(minSize.width, width + newPoint.x
- basePoint.x);
width = newWidth;
}
if ((direction & SOUTH) == SOUTH) {
int novoAlto;
novoAlto = Math.max(minSize.height, height + newPoint.y
- basePoint.y);
height = novoAlto;
}
if ((direction & WEST) == WEST) {
int newWidth, newX;
newWidth = Math.max(minSize.width, width - newPoint.x
+ basePoint.x);
newX = Math.min(x + width - minSize.width, x + newPoint.x
- basePoint.x);
// Changing coordenates of new base point to refer to the new component position
newBasePointX -= newX - x;
x = newX;
width = newWidth;
}
if ((direction & NORTH) == NORTH) {
int newHeigth, newY;
newHeigth = Math.max(minSize.height, height - newPoint.y
+ basePoint.y);
newY = Math.min(y + height - minSize.height, y + newPoint.y
- basePoint.y);
// Changing coordenates of new base point to refer to the new component position
newBasePointY -= newY - y;
y = newY;
height = newHeigth;
}
controlledComponent.setBounds(x, y, width, height);
basePoint = new Point(newBasePointX, newBasePointY);
}
#Override
public void mouseMoved(MouseEvent e) {
Component originator = e.getComponent();
if (direction == 0) {
sourceCursor = originator.getCursor();
}
calculateDirection(e.getPoint(), e.getComponent().getSize());
setCursor(e.getComponent());
basePoint = e.getPoint();
}
private void setCursor(Component component) {
if (direction == 0) {
component.setCursor(sourceCursor);
} else {
int cursorType = cursors.get(direction);
Cursor cursor = Cursor.getPredefinedCursor(cursorType);
component.setCursor(cursor);
}
}
private void calculateDirection(Point point, Dimension componentSize) {
direction = 0;
if (point.x < dragInsets.left) {
direction |= WEST;
}
if (point.y < dragInsets.top) {
direction |= NORTH;
}
if (point.x > componentSize.width - dragInsets.right) {
direction |= EAST;
}
if (point.y > componentSize.height - dragInsets.bottom) {
direction |= SOUTH;
}
}
}
import java.awt.Insets;
import javax.swing.JComponent;
public class FrameComponent extends JComponent {
private static final long serialVersionUID = 3383070502274306213L;
private Insets insets;
#Override
public boolean contains(int x, int y) {
return x < insets.left || y < insets.top || getHeight() - y < insets.bottom || getWidth() - x < insets.right;
}
public FrameComponent(Insets insets) {
this.insets = insets;
}
}
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GUI {
private JFrame compoundFrame;
private JPanel backgroundPanel;
Dimension gUISize = new Dimension(400, 400);
public GUI() {
buildResizeableFrame();
}
public void activate() {
compoundFrame.setVisible(true);
}
private void buildResizeableFrame() {
compoundFrame = new JFrame();
FrameComponent frame = new FrameComponent(new Insets(5, 5, 5, 5));
backgroundPanel = new JPanel();
compoundFrame.setLayout(null);
compoundFrame.add(frame);
compoundFrame.add(backgroundPanel);
setFrameSizeController(frame, backgroundPanel);
setFrameController(frame);
setBackgroundPanelController(backgroundPanel);
Dimension dimPant = Toolkit.getDefaultToolkit().getScreenSize();
compoundFrame.setBounds(dimPant.width / 4, dimPant.height / 4, dimPant.width / 2, dimPant.height / 2);
compoundFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
compoundFrame.setUndecorated(true);
}
private void setFrameSizeController(FrameComponent frame, JPanel panel) {
compoundFrame.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
Dimension sizeIn = ((JFrame) e.getComponent()).getContentPane().getSize();
frame.setSize(sizeIn);
panel.setSize(sizeIn);
}
});
}
private void setFrameController(FrameComponent frame) {
ComponentBorderDragger controller = new ComponentBorderDragger(compoundFrame,
new Insets(5, 5, 5, 5), new Dimension(10, 10));
frame.addMouseMotionListener(controller);
}
private void setBackgroundPanelController(JPanel panel) {
panel.addMouseMotionListener(new BackgroundComponentDragger(compoundFrame));
}
public static void main(String[] args) {
new GUI().activate();
}
}
Note: This code sets a null LayoutManager and a listener to the container to resize the inner component when needed. This practice is discouraged. This logic should be moved to a custom layout manager.
Add this to your frame after selecting "undecorated" option (below uses a jbutton from the main menu to open a new undecorated input form called PlumbingPRO that has a border and is draggable). I would add this to MAIN Method or at the class that has the "initComponents();" at the beginning of the java file if using within the main form. If using for a follow-on form, the below should work from the button selection. Make sure you do your "imports" for the below actions (BorderFactory, FrameDragListener, addmouselistener, addMouseMotionListener) in the form that has the button selection and not the follow-on form.
private void jbtn_PLUMBINGActionPerformed(java.awt.event.ActionEvent evt) {
PlumbingPRO frame = new PlumbingPRO();
frame.getRootPane().setBorder(BorderFactory.createMatteBorder(3, 3, 3, 3,
Color.DARK_GRAY));
FrameDragListener frameDragListener = new FrameDragListener(frame );
frame.addMouseListener(frameDragListener);
frame.addMouseMotionListener(frameDragListener);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
You might want to try this, but you need to add a functionality to close the window.
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.Map.Entry;
import javax.swing.*;
public class AppWindow extends JFrame {
Map<Boolean, String> mousePoint;
private String direction;
public AppWindow() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 570, 337);
setUndecorated(true);
getContentPane().setBackground(new Color(33, 115, 70));
getContentPane().setLayout(null);
setLocationRelativeTo(null);
setVisible(true);
setMinimumSize(new Dimension(100, 100));
getContentPane().addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
mousePoint = new HashMap<Boolean, String>();
mousePoint.put(e.getY() < 5, "N");
mousePoint.put(e.getX() > (getWidth() - 5), "E");
mousePoint.put(e.getY() > (getHeight() - 5), "S");
mousePoint.put(e.getX() < 5, "W");
mousePoint.put(e.getY() < 5 && e.getX() > (getWidth() - 5), "NE");
mousePoint.put(e.getY() > (getHeight() - 5) && e.getX() > (getWidth() - 5), "SE");
mousePoint.put(e.getY() > (getHeight() - 5) && e.getX() <= 5, "SW");
mousePoint.put(e.getY() < 5 && e.getX() < 5, "NW");
for (Entry<Boolean, String> item : mousePoint.entrySet()) {
if (item.getKey()) {
direction = item.getValue();
switch (item.getValue()) {
case "N":
setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
break;
case "E":
setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
break;
case "S":
setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
break;
case "W":
setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
break;
case "NE":
setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR));
break;
case "SE":
setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
break;
case "SW":
setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR));
break;
case "NW":
setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR));
break;
}
} else {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (!getCursor().equals(Cursor.getDefaultCursor())) {
switch (direction) {
case "N":
if (e.getYOnScreen() > getY()) {
setBounds(getX(), e.getYOnScreen(), getWidth(), getHeight() - (e.getYOnScreen() - getY()));
} else {
setBounds(getX(), e.getYOnScreen(), getWidth(), getHeight() + (getY() - e.getYOnScreen()));
}
break;
case "E":
setBounds(getX(), getY(), e.getX(), getHeight());
break;
case "S":
setBounds(getX(), getY(), getWidth(), e.getY());
break;
case "W":
if (e.getXOnScreen() > getX()) {
setBounds(e.getXOnScreen(), getY(), getWidth() - (e.getXOnScreen() - getX()), getHeight());
} else {
setBounds(e.getXOnScreen(), getY(), getWidth() + (getX() - e.getXOnScreen()), getHeight());
}
break;
case "NE":
setBounds(getX(), getY(), e.getX(), getHeight());
if (e.getYOnScreen() > getY()) {
setBounds(getX(), e.getYOnScreen(), getWidth(), getHeight() - (e.getYOnScreen() - getY()));
} else {
setBounds(getX(), e.getYOnScreen(), getWidth(), getHeight() + (getY() - e.getYOnScreen()));
}
break;
case "SE":
setBounds(getX(), getY(), e.getX(), e.getY());
break;
case "SW":
setBounds(getX(), getY(), getWidth(), e.getY());
if (e.getXOnScreen() > getX()) {
setBounds(e.getXOnScreen(), getY(), getWidth() - (e.getXOnScreen() - getX()), getHeight());
} else {
setBounds(e.getXOnScreen(), getY(), getWidth() + (getX() - e.getXOnScreen()), getHeight());
}
break;
case "NW":
if (e.getYOnScreen() > getY()) {
setBounds(getX(), e.getYOnScreen(), getWidth(), getHeight() - (e.getYOnScreen() - getY()));
} else {
setBounds(getX(), e.getYOnScreen(), getWidth(), getHeight() + (getY() - e.getYOnScreen()));
}
if (e.getXOnScreen() > getX()) {
setBounds(e.getXOnScreen(), getY(), getWidth() - (e.getXOnScreen() - getX()), getHeight());
} else {
setBounds(e.getXOnScreen(), getY(), getWidth() + (getX() - e.getXOnScreen()), getHeight());
}
break;
}
}
}
});
}
}
I am just starting to put together a logging tool for my own use that would log statistics from gym/running and the only experience I have with swing/awt is active rendering for games where you have full control over the Graphics2D object and don't rely on implementing swing components with overriden paints.
Anyway, I was hoping to create a dummy JComponent that I can add to one of my panels (this panel will display graphics, statistics etc depending on what I select from another different sidepanel with options) that does nothing else but listen for mouseevents inside the panel mentioned earlier and draws a selection rectangle on mousedrags so that I can zoom in the data if higher resolutions exist. I just don't know how, I have added the component to the panel but it registers nothing inside the panel, instead it seems to have a local space that is limited to the bottom of the panel/frame.
Here is the component
package gui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JComponent;
#SuppressWarnings("serial")
public class MarkerRectangle extends JComponent implements MouseListener,
MouseMotionListener {
private boolean draw;
private int startX, endX, startY, endY;
private Color color = new Color(0, 255, 0, 100);
public MarkerRectangle(int width, int height) {
setPreferredSize(new Dimension(width, height));
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse clicked# " + e.getX() + "," + e.getY());
}
#Override
public void mouseEntered(MouseEvent e) {
System.out.println("Mouse entered # " + e.getX() + "," + e.getY());
}
#Override
public void mouseExited(MouseEvent e) {
System.out.println("Mouse left # " + e.getX() + "," + e.getY());
}
#Override
public void mousePressed(MouseEvent e) {
System.out.println("Mouse pressed# " + e.getX() + "," + e.getY());
}
#Override
public void mouseReleased(MouseEvent e) {
System.out.println("Mouse was released # " + e.getX() + "," + e.getY());
}
#Override
public void mouseDragged(MouseEvent e) {
System.out.println("Mouse being dragged, currently# " + e.getX() + ","
+ e.getY());
}
#Override
public void mouseMoved(MouseEvent e) {
System.out.println("I registered a move# " + e.getX() + "," + e.getY());
}
#Override
// Draw rectangle
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.dispose();
}
}
The panel
public class GraphPane extends JPanel {
public GraphPane(Graph graph) {
this.add(graph);
this.add(new MarkerRectangle(800, 600));
this.setBackground(Color.gray);
this.setPreferredSize(new Dimension(800, 600));
}
}
The graph, holds random data atm
public class Graph extends JComponent {
private GeneralPath data;
private Stroke stroke;
public Graph() {
this.data = new GeneralPath();
this.stroke = new BasicStroke(3f);
this.setPreferredSize(new Dimension(750, 550));
init();
}
private void init() {
data.moveTo(0, 0);
double cntr = 0;
double[][] points = new double[10][1];
for (double[] point : points) {
cntr += 100;
point[0] = Math.random() * 100;
point[1] = Math.random() * 100;
data.lineTo(cntr, point[1]);
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(stroke);
g2d.draw(data);
g2d.dispose();
}
}
I want to implement something like the above because eventually I imagine the GUI to become quite complex and simple events like drawing a rectangle to mark data should not be in the main controller (so as to prevent a lot of if-tests and clutter in code).
Screenshot of what I get:
What I want:
EDIT
While the accepted answer below is the better solution I am posting this in the event that someone may want to use it. It will not work if you resize smaller the prefferedSize.
public class Test {
public static void main(String[] args) {
GeneralJFrame frame = new GeneralJFrame(1200, 800);
frame.addPanel(new GraphPane(new Graph()), BorderLayout.CENTER);
frame.addPanel(new ButtonPane(), BorderLayout.SOUTH);
frame.addPanel(new ButtonPane(), BorderLayout.SOUTH);
frame.addPanel(new ButtonPane(), BorderLayout.WEST);
frame.addPanel(new ButtonPane(), BorderLayout.EAST);
frame.addPanel(new ButtonPane(), BorderLayout.NORTH);
frame.start();
}
}
public class GraphPane extends JPanel {
public GraphPane(Graph graph) {
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = GridBagConstraints.REMAINDER;
c.gridheight = GridBagConstraints.REMAINDER;
c.gridx = 0;
c.gridy = 0;
this.setLayout(new GridBagLayout());
this.add(graph);
this.add(new MarkerRectangle(), c);
this.setBackground(new Color(205, 201, 201));
}
}
public class MarkerRectangle extends JComponent implements MouseListener,
MouseMotionListener {
private boolean draw;
private int startX, endX, startY, endY;
public MarkerRectangle() {
this.addMouseListener(this);
this.addMouseMotionListener(this);
setOpaque(false);
setPreferredSize(new Dimension(800, 600));
}
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
draw = true;
}
#Override
public void mouseReleased(MouseEvent e) {
draw = false;
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
endX = e.getX();
endY = e.getY();
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
}
#Override
// Draw rectangle
protected void paintComponent(Graphics g) {
System.out.println(getSize());
if (!draw)
return;
int w = endX-startX;
int h = endY - startY;
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(new Color(255, 165, 0));
g2d.fillRect(startX, startY, w, h);
g2d.dispose();
}
}
public class ButtonPane extends JPanel {
public ButtonPane() {
add(new JButton("HELLO"));
setBackground(Color.gray);
setBorder(BorderFactory.createEtchedBorder(Color.white,
Color.gray.darker()));
}
}
public class GeneralJFrame {
private JFrame frame;
public GeneralJFrame(int width, int height) {
this.frame = new JFrame("Le Muscles");
this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void addPanel(JPanel panel, String location) {
this.frame.add(panel, location);
}
public void start() {
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Outputs: (orange is dragged with mouse)
I still don't fully understand your question. As I see it, you've
created several JPanels
Given one JPanel a MouseListener and MouseMotionListener
You've added that JPanel to the bottom of another JPanel.
The JPanel that's sitting on the bottom registers all mouse events as it has been told to do
So your program is behaving as expected based on your code.
The question I have is this: how is it not behaving as you expect it to?
If you expect that adding a JPanel with MouseListeners and MouseMotionListeners attached will result in all the JPanels of the GUI to be listened to, well of course that won't happen. To have more of the GUI register mouse events, you'll have to add MouseListeners and MouseMotionListeners to those components. And that is my answer so far to your question as I see it. If I didn't answer the true question you currently face, then please clarify it for us.
You state:
What I want is an invisible (transparent) panel on top of the blue one in the above screenshot that is just as large as the blue one, not a subpanel that is sitting in the bottom. I want the blue one to contain this one (should not be a problem since it is just a jcomponent). What I hope to achieve is a sort over "invisible" overlay that registers mousevents so I don't have to implement these events in the blue panel.
Consider using a JLayer for this. As per the JLayer API:
JLayer is a good solution if you only need to do custom painting over compound component or catch input events from its subcomponents.
OK, I've experimented with it a bit and came up with something like this:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Path2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import javax.swing.*;
import javax.swing.plaf.LayerUI;
#SuppressWarnings("serial")
public class GraphPane2 extends JPanel {
private static final int GRAPH_WIDTH = 1000;
private static final int GRAPH_HEIGHT = 750;
private Graph2 graph2 = new Graph2(GRAPH_WIDTH, GRAPH_HEIGHT);
public GraphPane2() {
LayerUI<Graph2> myLayerUI = new MyLayerUI<Graph2>();
JLayer<Graph2> panelLayer = new JLayer<Graph2>(graph2, myLayerUI);
setLayout(new BorderLayout());
add(panelLayer);
myLayerUI.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (MyLayerUI.MOUSE_RELEASED.equals(evt.getPropertyName())) {
Rectangle rect = (Rectangle) evt.getNewValue();
System.out.println(rect);
}
}
});
}
private static void createAndShowGui() {
GraphPane2 mainPanel = new GraphPane2();
JFrame frame = new JFrame("Graph Pane2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class MyLayerUI<V extends JComponent> extends LayerUI<V> {
private static final Color FILL_COLOR = new Color(0, 128, 0, 128);
public static final String MOUSE_RELEASED = "mouse released";
private Point pressedPt;
private Point draggedPt;
private Rectangle rect;
#Override
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
if (rect != null) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(FILL_COLOR);
g2.fill(rect);
}
}
public void installUI(JComponent c) {
super.installUI(c);
((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK);
}
public void uninstallUI(JComponent c) {
super.uninstallUI(c);
((JLayer)c).setLayerEventMask(0);
}
#Override
public void eventDispatched(AWTEvent e, JLayer<? extends V> l) {
MouseEvent mEvt = (MouseEvent) e;
int id = mEvt.getID();
int btn = mEvt.getButton();
if (id == MouseEvent.MOUSE_PRESSED && btn == MouseEvent.BUTTON1) {
pressedPt = mEvt.getPoint();
rect = new Rectangle(pressedPt.x, pressedPt.y, 0, 0);
}
if (id == MouseEvent.MOUSE_PRESSED && btn != MouseEvent.BUTTON1) {
pressedPt = null;
}
if (id == MouseEvent.MOUSE_DRAGGED && pressedPt != null) {
draggedPt = mEvt.getPoint();
int x = Math.min(draggedPt.x, pressedPt.x);
int y = Math.min(draggedPt.y, pressedPt.y);
int width = Math.abs(draggedPt.x - pressedPt.x);
int height = Math.abs(draggedPt.y - pressedPt.y);
rect = new Rectangle(x, y, width, height);
}
if (id == MouseEvent.MOUSE_RELEASED && pressedPt != null) {
draggedPt = mEvt.getPoint();
int x = Math.min(draggedPt.x, pressedPt.x);
int y = Math.min(draggedPt.y, pressedPt.y);
int width = Math.abs(draggedPt.x - pressedPt.x);
int height = Math.abs(draggedPt.y - pressedPt.y);
rect = new Rectangle(x, y, width, height);
firePropertyChange(MOUSE_RELEASED, null, rect);
}
l.repaint();
}
}
#SuppressWarnings("serial")
class Graph2 extends JPanel {
private static final int MAX_DATA_POINTS = 100;
private static final int STEP = 10;
private static final Stroke STROKE = new BasicStroke(3f);
private Path2D path2D;
private int width;
private int height;
private int[] data = new int[MAX_DATA_POINTS + 1];
private Random random = new Random();
public Graph2(int width, int height) {
this.width = width;
this.height = height;
init();
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
path2D = new Path2D.Double();
int w = getWidth();
int h = getHeight();
double x = 0;
double y = ((double) MAX_DATA_POINTS - data[0]) * h
/ MAX_DATA_POINTS;
path2D.moveTo(x, y);
for (int i = 1; i < data.length; i++) {
x = (i * w) / (double) MAX_DATA_POINTS;
y = ((double) MAX_DATA_POINTS - data[i]) * h
/ (double) MAX_DATA_POINTS;
path2D.lineTo(x, y);
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (path2D != null) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(STROKE);
g2d.draw(path2D);
}
};
private void init() {
// create and fill random data
data[0] = 0;
boolean up = true;
// max and min data values -- used for normalization
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int i = 1; i < data.length; i++) {
up = random.nextInt(4) < 3 ? up : !up;
if (up) {
data[i] = data[i - 1] + random.nextInt(STEP);
} else {
data[i] = data[i - 1] - random.nextInt(STEP);
}
if (data[i] > max) {
max = data[i];
}
if (data[i] < min) {
min = data[i];
}
}
// normalize the data
for (int i = 0; i < data.length; i++) {
int datum = (MAX_DATA_POINTS * (data[i] - min)) / (max - min);
data[i] = datum;
}
}
}
This will look like: