I have a JFrame, which contains just a JPanel.
I add an mouse event to the JPanel.
But the whole JFrame gets the same mouse event.
Here is my code:
public class TestSwing extends JPanel {
public TestSwing() {
super.setSize(20, 20);
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
System.out.println(me);
}
});
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new TestSwing());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setVisible(true);
}
}
I set the size of the JPanel (20, 20), but no matter where I click, the mouse event will always be triggered.
You're adding that JPanel to the JFrame's contentPane, a component that uses BorderLayout, a layout which does not respect size or even for the most part preferred size, and so the JPanel will fill the entire JFrame's contentPane. Give the contentPane a FlowLayout and set the JPanel's preferred size and you'll see a difference. In the future, give the JPanel a Border to see its boundaries. This will make debugging this easy.
If you don't tell it otherwise, your JFrame will have BorderLayout like this:
Now if you furthermore don't tell your Panel where to go, it wil go into CENTER and thus be resized to fill whole content area.
For checking MouseEvent on only one JPanel I suggest you add another JPanel (maybe with different background?) to other area:
frame.getContentPane().add(new TestSwing(), BorderLayout.CENTER);
JPanel left = new JPanel();
left.setBackground(Color.red);
frame.getContentPane().add(left, BorderLayout.LEFT);
Size set by setSize() is only valid until it's recalculated based on Layout and other properties.
Related
I want to use a JLabel in a very simple environment but I'm wondering why I have to set the location on every repaint.
Code:
public class Example {
public static void main(String[] args) {
JFrame frame = buildFrame();
TestPane pane = new TestPane();
frame.add(pane);
while (true) {
pane.repaint();
frame.setVisible(true);
}
}
private static JFrame buildFrame() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(480, 272);
frame.setVisible(true);
return frame;
}
}
public class TestPane extends JPanel {
JLabel testLabel = new JLabel("TEST");
TestPane() {
super();
add(testLabel);
testLabel.setLocation(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
testLabel.setLocation(200, 200); // without this line, the label will always be at the top center
}
}
The loop-based layout comes from various animations with images I'm doing. Why does the repaint always reset the location of all labels so I have to setLocation on every paintComponent?
why I have to set the location on every repaint.
You don't. Actually, you should never set the position or any kind of constraint of a component inside paintComponent method. paintComponent method is only for painting, not for orientation or anything else.
When you jpanel.add(myComponent, constraints) component's position will be decided by container's current LayoutManager. (When you jpanel.add(myComponent); without any constraints, the default constraints will take place, with every layout manager having its own default).
The label is placed at the top of the panel because you do not set the layout of the panel, so it has its default, which is FlowLayout. In order to change it you will have to use another layout manager with the proper constraints.
For example, in order to place it at the center of the panel, you must do:
jpanel.setLayout(new BorderLayout());
jpanel.add(myLabel,BorderLayout.CENTER);
Finally doing while(true) inside the Thread where you GUI is running, it will hang the thread, means that the GUI will be "frozen" since events cannot take place.
How to resize the inputpanel and gamepanel so it can take the whole frame? the inputpanel.setsize() wont work and the other problem is that the gamepanel wont display its background image.
what I did is I added a mainpanel to the frame that contains the other 2 panel the inputpanel and the gamepanel. Both panels displays with their borders but the size is very small and I needed them to fit the screen
public class GameMaster {
JFrame frame = new JFrame();
JPanel gamepanel = new Gamepanel();
JPanel mainpanel = new JPanel();
JPanel inputpanel = new JPanel();
JButton button1 = new JButton("Hoy!");
public GameMaster(){
frame.setTitle("gayEdward vs Charlie's angels");
frame.setSize(800,600);
frame.setVisible(true);
frame.setDefaultCloseOperation(3);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setLayout(new FlowLayout());
gamepanel.setSize(600, 600);
inputpanel.setSize(200, 600);
mainpanel.setSize(800, 600);
gamepanel.setBorder(BorderFactory.createLineBorder(Color.black));
inputpanel.setBorder(BorderFactory.createLineBorder(Color.black));
mainpanel.setLayout(new FlowLayout());
mainpanel.add(gamepanel);
mainpanel.add(inputpanel);
frame.add(mainpanel);
}
This is the Gamepanel class where The Gamepanel should set the image as its background
public class Gamepanel extends JPanel {
Image image;
public Gamepanel(){
try
{
image = ImageIO.read(getClass().getResourceAsStream("C:\\Users\\phg00159\\workspace\\Mp2\\pvzbg.jpg"));;
}
catch (Exception e) { /*handled in paintComponent()*/ }
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
if (image != null)
g.drawImage(image, 0,0,this.getWidth(),this.getHeight(),this);
}
}
You need to override getPreferredSize() in the GamePanel class. You should always do this when doing custom painting. The panel has no preferred size because it has no components. And the layout you are using FlowLayout takes the preferred size into consideration. Then just pack() the frame, instead of setting the size. Also note that setSize() for components is generally used for null layouts (which I strongly am against). With layout managers, they are determine by preferredSize
public class GamePanel extends JPanel {
private Image image;
#Override
public Dimension getPreferredSize() {
return new Dimension(image.getWidth(this), image.getHeight(this));
// or whatever you want the size to be
}
}
Aside:
/*handled in paintComponent()*/ - A null check isn't a substitute for an empty catch block.
frame.setVisible() should the last thing you do after adding all your components
UPDATE
As #MadProgrammer pointed out to me, you want the panel to resize with the frame. In order to do that, you need to use a different layout manager. The two that won't respect the preferred size of your panels will be either GridLayout or BorderLayout. These will "stretch your components to fit". So choose one of them, or a combination of both, seeing as you have nested panels. But you should also keep the overriden getPreferredSize() and still pack() your frame This will give you the initial size of the frame, based on your preferred size
More specifically, how to adjust JFrame size by its contentPane.
Here is the case, I am doing a 400*400 JPanel and I need it to fit in the JFrame. However if I set JFrame setSize(400, 400), some part of the JPanel would be hid due to the space occupied by the upper windows title bar.
I know I can just measure the border and the size of the title bar. I just want to know if there is better way to do.
Here is the solution that takes both Hovercraft Full Of Eels and MadProgrammer answer.
public class Window extends JFrame {
private Window() {
createUI();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Window();
}
});
}
private void createUI() {
setContentPane(buildMainPanel());
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
}
private JPanel buildMainPanel() {
JPanel mainPanel = new JPanel();
mainPanel.setPreferredSize(new Dimension(500, 640));
mainPanel.setLayout(null);
mainPanel.add(new Canvas(0, 0));
return mainPanel;
}
}
However if I set JFrame setSize(400, 400), some part of the JPanel would be hid due to the space occupied by the upper windows title bar.
You're making things too hard for yourself since the easiest solution is to simply not set the JFrame size. Instead call pack() on the JFrame after adding all components and before calling setVisible(true) and let it size itself to the optimum size for its components and layout managers.
Override the panel's getPreferredSize method and return new Dimension(400, 400).
On the frame call pack. When called, pack will ask the content pane for it's preferred size, which is normally calculated by the layout manager (recursively ask each container for it's preferred size).
This will size the window so that's viewable area meets (as much as its possible to do so) the preferred size of it's content.
I am trying to place a JPanel on top of another JPanel which contains a JTextArea and a button and i want to the upper apnel to be transparent. I have tried it by making the setOpaque(false) of the upper panel. but it is not working. Can anyone help me to get through this? Thanks in advance!
public class JpanelTest extends JPanel
{
public JpanelTest()
{
super();
onInit();
}
private void onInit()
{
setLayout(new BorderLayout());
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(new JTextArea(100,100),BorderLayout.CENTER);
panel.add(new JButton("submit"),BorderLayout.SOUTH);
JPanel glass = new JPanel();
glass.setOpaque(false);
add(panel,BorderLayout.CENTER);
add(glass,BorderLayout.CENTER);
setVisible(true);
}
public static void main(String args[])
{
new JpanelTest();
}
}
Indeed, it would be useful to tell the reason why you want panels one over another.
Starting with your code, and changing it a lot, I got it to work, but it might not do what you expect...
import java.awt.*;
import javax.swing.*;
public class Test extends JFrame
{
public Test()
{
super();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 200);
onInit();
setVisible(true);
}
private void onInit()
{
JLayeredPane lp = getLayeredPane();
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(new JTextArea(), BorderLayout.CENTER);
panel.add(new JButton("Submit"), BorderLayout.SOUTH);
panel.setSize(300, 150); // Size is needed here, as there is no layout in lp
JPanel glass = new JPanel();
glass.setOpaque(false); // Set to true to see it
glass.setBackground(Color.GREEN);
glass.setSize(300, 150);
glass.setLocation(10, 10);
lp.add(panel, Integer.valueOf(1));
lp.add(glass, Integer.valueOf(2));
}
public static void main(String args[])
{
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new Test();
}
});
}
}
If totally transparent, well, it is like it isn't here! When opaque, it just covers some of the GUI, but doesn't prevent mouse clicks, for example.
1) there are a few ways, there no issue to put JPanel, with covering full JFrames/JPanel area or only part of Rectangle / Dimension that returns JFrames/JPanel
use JLayer(Java7) based on JXLayer (Java6)
use GlassPane
use JViewport
use OverlayLayout
use transucent JDialog / JWindow
2) everything depends of if you want to protect against mouse and key events from the top layer to bottom, or not (to avoiding redispatch events from - to and vice versa)
Check out this tutorial on using Swing Root Panes.
The glass pane is useful when you want to be able to catch events or paint over an area that already contains one or more components. For example, you can deactivate mouse events for a multi-component region by having the glass pane intercept the events. Or you can display an image over multiple components using the glass pane.
I have a JFrame, in this JFrame I have a JPanel that I draw on, this Panel can be any size and so I placed it into a JScrollpane to let me scroll when the panel is larger than the window screen size.
Unfortunately does not work as I expected:
Making the JFrame window smaller than the JPanel size does not show scroll bars
The JScrollPane size now seems locked to the size of the JPanel I have added to it, where as before it resized to the bounds of it's JFrame window (it still kinda does this but only vertically now?!)
The JPanel seems to assume the size of the JScrollpane regardless of what I set for preferred size
I am sure I'm doing something stupid, if someone could point out what I would be most grateful!
JPanel imageCanvas = new JPanel(); // 'Canvas' to draw on
JScrollPane scrollPane = new JScrollPane();
// set size of 'canvas'
imageCanvas.setMinimumSize(new Dimension(100,100));
// Scroll pane smaller then the size of the canvas so we should get scroll bars right?
scrollPane.setMinimumSize(new Dimension(50,50));
// Add a border to 'canvas'
imageCanvas.setBorder(BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0)));
scrollPane.setViewportView(imageCanvas);
setPreferredSize() is the trick, setMinimumSize() and even setSize() on the component will be ignored by JScrollPane. Here's a working example using a red border.
import java.awt.*;
import javax.swing.*;
public class Scroller extends JFrame {
public Scroller() throws HeadlessException {
final JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createLineBorder(Color.red));
panel.setPreferredSize(new Dimension(800, 600));
final JScrollPane scroll = new JScrollPane(panel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
add(scroll, BorderLayout.CENTER);
setSize(300, 300);
setVisible(true);
}
public static void main(final String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Scroller().setVisible(true);
}
});
}
}
// suggest a size of 'canvas'
_ImageCanvas.setPreferredSize(new Dimension(100,100));
// Scroll pane smaller then the size of the canvas so we should get scroll bars right?
_ScrollPane.setPreferredSize(new Dimension(50,50));
// ..later
_Frame.pack();
Set preferred size on the canvas.
Increase dimensions 100,100 is too small atleast on my computer.
You may want to use new GridLayout(1,1); for you JFrame if you want the scrollpane to expand when you expand the frame.
As far as I remember there are 2 options:
define the preferredSize of _ImageCanvas
create a subclass of JPanel and implement Scrollable: http://docs.oracle.com/javase/7/docs/api/javax/swing/Scrollable.html
For more details, see the Javadoc:
http://docs.oracle.com/javase/7/docs/api/javax/swing/JScrollPane.html
Check out the Scrollable interface, this may help with the sizing issues.
These two method maybe helpful:
boolean getScrollableTracksViewportWidth();
boolean getScrollableTracksViewportHeight();