just a short question: Is it possible to add a background color to a JComponent when it is added directly onto a JFrame using null layout? The size and position of the component are set by setBounds() and i know that the background color will not be displayed using this setup. (I know you should always use layout managers, but in this case i want to prevent this).
JComponent is transparent by default, you'd either need to change its opaque state or use a JPanel
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
TestPane pane = new TestPane();
pane.setBounds(10, 10, 100, 100);
JFrame frame = new JFrame("Testing");
frame.setLayout(null); // This is bad, but it proofs my point
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(pane);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JComponent {
public TestPane() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
setOpaque(!isOpaque());
repaint();
}
});
setBackground(Color.BLUE);
setBorder(new LineBorder(Color.RED));
}
}
}
null layouts are bad news, I don't condone them and you should avoid using them, the example above simply proves the point that it's the JComponents opaque state which needs to be changed
Why is it frowned upon to use a null layout in SWING? is a nice read about why you should avoid using null layouts.
If you want more control, write your own.
Related
I'm working on an application that allows me to show and hide split planes.
I've read some articles on how to get this but its not what I'm looking for.
here's the code Ive written:
Im currently using netbeans.
private void jSplitPane1MouseEntered(java.awt.event.MouseEvent evt) {
if(MouseInfo.getPointerInfo().getLocation() == jSplitPane1.getLeftComponent().getLocation()){
jSplitPane1.setDividerLocation(100);
System.out.println("Mouse Entered");
}else{
jSplitPane1.setDividerLocation(20);
System.out.println("Mouse Exited");
}
}
I have referred to these posts:
How to make JSplitPane auto expand on mouse hover?
Get Mouse Position
What I want to happen is when I mouse over the left side of the jSplitPane, I would get the divider to extend to 100 as per my first if statement, and when it exists the left side, it contracts back to divider location 20.
This is really, really tricky.
You could use a MouseListener on the "left" component and monitor the mouseEntered and mouseExited events, but these will also get triggered when when you move into and out of a child component which has a MouseListener of it's own (like a JButton).
Okay, you could use a MouseMotionListener on the JSplitPane and monitor for the mouseMoved event and check where the mouse cursor is, but this goes to hell the moment the components (left/right) get their own MouseListener, as the MouseEvents are no longer delivered to the JSplitPane
So, one of the last options you have is to attach a global AWTListener to the event queue and monitor for events which occur on the JSplitPane itself, for example...
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
JSplitPane pane = new JSplitPane();
pane.setLeftComponent(makePane(Color.RED));
pane.setRightComponent(makePane(Color.BLUE));
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent event) {
if (event instanceof MouseEvent) {
MouseEvent me = (MouseEvent) event;
if (pane.getBounds().contains(me.getPoint())) {
System.out.println("Global Motion in the pane...");
me = SwingUtilities.convertMouseEvent(me.getComponent(), me, pane);
Component left = pane.getLeftComponent();
if (left.getBounds().contains(me.getPoint())) {
pane.setDividerLocation(100);
} else {
pane.setDividerLocation(20);
}
}
}
}
}, MouseEvent.MOUSE_MOTION_EVENT_MASK);
// You don't need this, this is to demonstrate
// that mouse events aren't hitting your component
// via the listener
pane.addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
System.out.println("Motion in the pane...");
Component left = pane.getLeftComponent();
if (left.getBounds().contains(e.getPoint())) {
pane.setDividerLocation(100);
} else {
pane.setDividerLocation(20);
}
}
});
pane.setDividerLocation(20);
add(pane);
}
protected JPanel makePane(Color background) {
JPanel pane = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
};
pane.setLayout(new GridBagLayout());
pane.add(new JButton("..."));
pane.setBackground(background);
pane.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("...");
}
});
return pane;
}
}
}
I wanted to create a fairly simple GUI program that switches between panels depending on buttons the user clicked. I searched around and came up with CardLayout being the best suggestion.
Basically in the examples of CardLayout, you create a "card" (a JPanel) and then add each component, like buttons, etc... and switch between the cards.
What I want to create is an object that is a "card" with all the components set up already, in a separate class, and just create an instance of that in the main program. I am a beginner and do not know the best design practices, so I didn't want to create my own class that extended JPanel, which I am pretty sure is terrible design.
You do it just like you would if you had create an instance of JPanel and add the components directly to it.
You need to ensure that the custom class extends from something JComponent or JPanel (preferably) and add them to the container like any other component, for example...
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestCard {
public static void main(String[] args) {
new TestCard();
}
public TestCard() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
final CardLayout cardLayout = new CardLayout();
final JPanel cardPane = new JPanel(cardLayout);
cardPane.add(new Card01(), "Card01");
cardPane.add(new Card02(), "Card02");
JToggleButton btnCard01 = new JToggleButton("#1");
JToggleButton btnCard02 = new JToggleButton("#2");
ButtonGroup bg = new ButtonGroup();
bg.add(btnCard01);
bg.add(btnCard02);
JPanel buttons = new JPanel();
buttons.add(btnCard01);
buttons.add(btnCard02);
btnCard01.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(cardPane, "Card01");
}
});
btnCard02.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
cardLayout.show(cardPane, "Card02");
}
});
btnCard01.setSelected(true);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(cardPane);
frame.add(buttons, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Card01 extends JPanel {
public Card01() {
setLayout(new GridBagLayout());
add(new JLabel("#1"));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class Card02 extends JPanel {
public Card02() {
setLayout(new GridBagLayout());
add(new JLabel("#2"));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
I have one outer panel, in the outer panel I have another jPanel placed on it.
if i do a right click on the inner panel, outer panel's right click action should happen. if i do left click on the inner panel, its own inner panel's click action should happen.
Is it possible to pass click event from one panel to another panel?
There are a number issues you need to resolve for this to work.
The first is understanding that a mouse event is contextual to the component that created it, in particular, the location information. The click point is the offset from the source components x/y position (which will be 0x0 for the mouse event). This means if you want to redispatch the event, you need to, at least, translate the location context into the parent components space.
The source component should also be changed. Failing to do this could cause issues for other parts of the API that may rely on it to make determinations (such as a popup, which will want to translate the location information from the component space to the screen space).
Secondly, you should make no assumptions about the parent. That is, you should make no assumption that the parent may or may not implement a mouse listener interfaces.
A possible solution would be to use SwingUtilities.convertMouseEvent to convert the MouseEvent raised in the inner panel to be compatible with the outer panel and then use Component#dispatchEvent to mimick the standard event handling process, for example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class TestTree {
public static void main(String[] args) {
new TestTree();
}
public TestTree() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new OutterPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class InnerPane extends JPanel {
public InnerPane() {
setBackground(Color.RED);
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Inner was clicked at : " + e.getPoint());
MouseEvent convertMouseEvent = SwingUtilities.convertMouseEvent(e.getComponent(), e, getParent());
getParent().dispatchEvent(convertMouseEvent);
}
});
}
}
public class OutterPane extends JPanel {
public OutterPane() {
setLayout(new BorderLayout());
setBorder(new EmptyBorder(10, 10, 10, 10));
add(new InnerPane());
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("Outter was clicked at : " + e.getPoint());
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
Have you tried something like in your inner panel?
void mouseClicked(MouseEvent e) {
if ( e.getButton() == MouseEvent.BUTTON2 ) {
outter.mouseClicked( e );
}
else {
// do job for your inner panel
}
}
Below code worked for me
JPanel parent = (JPanel) me.getComponent().getParent();
MouseMotionListener[] ml = parent.getMouseMotionListeners();
ml[0].mouseClicked(me);
Thanks all
I am making a java application that includes a JWindow. I want to be able to track the mouse without the user having to click the window after going to another window.
Your question is little vague on why you want to continue processing the mouse once it's left the JWindow...but
You have two (basic) choices when it comes to mointoring the mouse outside of your application, you can use a JNI/JNA solution or you can poll MouseInfo.
The following demonstrates the latter, using MouseInfo and a javax.swing.Timer to update a label...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.MouseInfo;
import java.awt.PointerInfo;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MouseWindow {
public static void main(String[] args) {
new MouseWindow();
}
public MouseWindow() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JLabel label;
public TestPane() {
setLayout(new BorderLayout());
label = new JLabel();
label.setFont(label.getFont().deriveFont(48f));
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
add(label);
updateMouseInfo();
Timer timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updateMouseInfo();
}
});
timer.start();
}
protected void updateMouseInfo() {
PointerInfo pi = MouseInfo.getPointerInfo();
label.setText(pi.getLocation().x + "x" + pi.getLocation().y);
}
}
}
Updated
You may also find Window#setAlwaysOnTop of help to keep the window ontop of the others, if support for the platform
I am pretty bad with english so please forgive me for grammatical mistakes. I am new in java swings, my intent is to create many jinternalframes dynamically and each jintenalframe is to be movable i.e. free to drag and be kept anywhere, which i have achieved through component mover class. Now the problem which i am facing is that i am unable to resize these internalframes. whenever i am resizing these jinternalFrames they are getting back to same size.
I have even registered with resizing event with component listener below code depicts that:
this.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent ce)
{
setDinamicSize(ce)
}
});
private void setDinamicSize(ComponentEvent ce)
{
JInternalFrame tempFrame = (JInternalFrame)ce.getSource();
tempFrame.setSize(new Dimension(tempFrame.getAlignmentX(),tempFrame.getAlignmenty()));
}
please help me out. thanks in advance
JDesktopPane is a container for JInternalFrames which takes care of things like positioning and (if you've constructed the internal frames correctly) resizing...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestDesktopPane {
public static void main(String[] args) {
new TestDesktopPane();
}
public TestDesktopPane() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JDesktopPane pane = new JDesktopPane();
JInternalFrame inFrame = new JInternalFrame("No Hands", true, true, true, true);
inFrame.setBounds(10, 10, 100, 100);
inFrame.setVisible(true);
pane.add(inFrame);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(pane);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Check out How to use Internal Frames for more details