Remove a JPanel with a JButton [JAVA] - java

I have the class with the Frame:
import java.awt.*;
import javax.swing.*;
public class Menu_Frame extends JFrame{
Menu_Panel menu_panel = new Menu_Panel();
public Menu_Frame(){
Toolkit kit = Toolkit.getDefaultToolkit();
Dimension screenSize = kit.getScreenSize();
int screenHeight = screenSize.height;
int screenWidth = screenSize.width;
setExtendedState(JFrame.MAXIMIZED_BOTH);
setPreferredSize(new Dimension(screenWidth, screenHeight));
setLocationByPlatform(true);
getContentPane().add(menu_panel);
}
}
Here i have the panel:
import java.awt.*;
import javax.swing.*;
public class Menu_Panel extends JPanel{
Play_Button play = new Play_Button();
public Menu_Panel() {
Toolkit kit = Toolkit.getDefaultToolkit();
Dimension screenSize = kit.getScreenSize();
int screenHeight = screenSize.height;
int screenWidth = screenSize.width;
setLayout(new BorderLayout());
setSize(screenWidth, screenHeight);
setLocation(0,0);
setBackground(Color.BLACK);
add(play);
}
}
And here i have the button class:
public class Play_Button extends JButton implements ActionListener{
private static final long serialVersionUID = -5408317246901761857L;
protected int size_x = 150;
protected int size_y = 75;
protected int location_x = 0;
protected int location_y = 0;
Font f= new Font("Helvetica", Font.BOLD, 30);
String title = "PLAY";
Menu_Frame frame;
Menu_Panel menu;
public Play_Button() {
setFont(new Font("Helvetica", Font.BOLD, 25));
setText(title);
Toolkit kit = Toolkit.getDefaultToolkit();
Dimension screenSize = kit.getScreenSize();
location_x = (screenSize.height/2)+180;
location_y = screenSize.width/5;
setBorder(new RoundedBorder(20));
setSize(size_x,size_y);
setLocation(location_x,location_y);
setBackground(Color.BLACK);
setForeground(Color.RED);
setFocusPainted(false);
setBorderPainted(false);
setContentAreaFilled(false);
setVisible(true);
JPanel panel = new JPanel();
panel.setSize(100,100);
panel.setLocation(100, 100);
panel.setBackground(Color.GREEN);
panel.setVisible(true);
addActionListener(this);
addMouseListener(new MouseAdapter() {
public void mouseEntered(MouseEvent e){
setBorderPainted(true);
setForeground(Color.RED);
}
public void mouseExited(MouseEvent e){
setBorderPainted(false);
}
});
}
#Override
public void actionPerformed(ActionEvent e) {
frame.getContentPane().remove(menu);
}
}
And Finally here i have the class for round the border of play_button:
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Insets;
import javax.swing.border.Border;
public class RoundedBorder implements Border {
private int radius;
RoundedBorder(int radius) {
this.radius = radius;
}
public Insets getBorderInsets(Component c) {
return new Insets(this.radius+1, this.radius+1, this.radius+2, this.radius);
}
public boolean isBorderOpaque() {
return true;
}
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
g.drawRoundRect(x, y, width-1, height-1, radius, radius);
}
}
Now, the panel doesn't disappear when i click the button, and i don't know why. I try with a CarLayout, with setVisible(false), but it doesn't work. How can i fix it?

Preambule...
I would advice against using Toolkit#getScreenSize this way, as it doesn't take into account additional OS elements, like the task bar or dock. As a general user recommendation, don't set the size of the main frame, instead simply allow the preferred size to be the packed size and expand the frame to it's OS maximum using setExtendedState as you have
setSize, setBounds, setLocation are all irrelevant while the components are under the control of a layout manager. Also, components are visible by default.
Core...
Removing a component is the opposite of adding one (no, seriously). Simply call remove on the container which contains the component, passing a reference of the component you want to remove. When you're done updating the UI, simply call revalidate and repaint on the container to trigger a layout and paint pass.
Having said that, generally speaking, it's much better to make use of a CardLayout, which provides you the ability to simply switch between different views.
See How to Use CardLayout for more details

The issue is with your actionPerformed method
public void actionPerformed(ActionEvent e)
{
frame.getContentPane().remove(menu);
}
frame and menu are declared fields of Play_Button, but are never set to anything
If you print out what they are, they should be null
When you create your button, make sure to set those two fields:
Menu_Panel menu_panel = new Menu_Panel();
menu_panel.play.menu = menu_panel;
menu_panel.play.frame = this;
While this may work, it is not great program flow

Related

Jcomponent paintcomponent not appearing on the panel

i am making a simple GUI in which small boxes should appear on the Jpanel according to their x,y coordinates. So i in my structure i have got three classes:
1: MyFrame which contains the main JFrame
2: MyPanel extends JPanel
3: Icon extends JComponent
In my MyFrame i want to have a MenuBar through which i can open a file of X,Y coordinates and below the menu bar i want to have the MyPanel which will have all the Icons for each X,Y coordinates. The first problem i have is that the Icon do not appear on MyPanel when i add the Icons.
My code can be seen below:
public class MyFrame {
private JFrame frame;
private MyPanel panel;
public MyFrame(){
panel = new MyPanel();
}
/*
*HERE GOES THE `FILE OPEN` LISTENER
* it creates `Coordinate` for each line
* passes the coordinate to panel.makeIcons()
*/
public void createGui(){
frame = new JFrame("Graph Editor");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(true);
//create, get and set the Jframe menu bar
//createMenuBar() returns a JMenuBar
frame.setJMenuBar(createMenuBar());
Container frame_pane = frame.getContentPane();
panel.setBounds(0, 0, frame.getWidth(), frame.getHeight());
frame_pane.add(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]){
MyFrame window = new MyFrame();
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
window.createGui();
}
});
}
}
Code For the panel for holding icons:
public class MyPanel extends JPanel{
private Set<Icon> points;
public MyPanel(){
setLayout(null);
setPreferredSize(new Dimension(600, 600));
setBackground(Color.YELLOW);
}
//gets called by `FILE OPEN` listener for each coordinate
public void makeIcons(Coordinate obj){
Icon temp = new Icon(obj);
points.add(temp);
//add the temp JComponent to this JPanel
this.add(temp);
}
}
Code for Icon which needs to be shown on the above panel:
public Icon extends JComponent{
private Coordinate location;
public Icon(Coordinate obj){
location = obj;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(location.getX(), location.getY(), 20, 20);
g.setColor(Color.BLACK);
g.drawRect(location.getX(), location.getY(), 20, 20);
}
}
First Problem: The Icons do not show up in the panel with the above code.
Second Problem: When i change the makeIcon method in MyPanel.class to below. It shows the Icons By the MenuBar erases them when the MenuBar appears on any of the icons:
public void makeIcons(Coordinate obj){
Icon temp = new Icon(obj);
points.add(temp);
//add the temp JComponent to this JPanel
this.add(temp);
temp.paintComponent(this.getGraphics());
revalidate();
}
Any help is appreciated. Thanks
Don't call paintComponent (or any paint) method yourself, ever. This is not how painting works.
The core reasons why a component won't be painted are because:
it's size is 0x0
it's invisible
it's not added to a container that is (indirectly) added to a native peer.
Based on my brief observation, I would say you're suffering from point number 1, in part due to the use of a null layout
Also, remember, when painting a component, the component's Graphics context has already been translated so that 0x0 is the top/left corner of the component. This means, based on your code, you'd most likely be painting beyond the visible bounds of the component any way.
So, you basically have two choices. Implement your own layout manager, which uses the Coordinate information to place the Icons with in the container (which would then need to override getPreferredSize in order to provide sizing hints) or, paint it yourself
Which might look something like this...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Graph Editor");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.add(new MyPanel());
frame.pack();
frame.setVisible(true);
}
});
}
public class Coordinate {
private int x;
private int y;
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
public class Icon {
private Coordinate coordinate;
public Icon(Coordinate coordinate) {
this.coordinate = coordinate;
}
public Coordinate getCoordinate() {
return coordinate;
}
public void paint(Graphics2D g2d) {
g2d.setColor(Color.RED);
g2d.fillRect(0, 0, 20, 20);
g2d.setColor(Color.BLACK);
g2d.drawRect(0, 0, 20, 20);
}
}
public class MyPanel extends JPanel {
private Set<Icon> points;
public MyPanel() {
points = new HashSet<>();
setLayout(null);
setPreferredSize(new Dimension(600, 600));
setBackground(Color.YELLOW);
}
//gets called by `FILE OPEN` listener for each coordinate
public void makeIcons(Coordinate obj) {
points.add(new Icon(obj));
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Icon icon : points) {
Graphics2D g2d = (Graphics2D) g.create();
Coordinate coordinate = icon.getCoordinate();
// I'd have a size component associated with the Icon
// which I'd then use to offset the context by half its
// value, so the icon is paint around the center of the point
g2d.translate(coordinate.getX() - 10, coordinate.getY() - 10);
icon.paint(g2d);
g2d.dispose();
}
}
}
}
I've not seeded any values, I'm lazy, but that's the basic idea

Can not add JComponent to JPanel

Have problem with adding class extended from JComponent to MyPanel class.
After choose from JComboBox list and press Start/Restart, the right panel doesnt update. Mean after adding to the Panel MyComponent class where is all drawing stuff. If someone can take a look and tell me when i am doing the mistakes or if its the different way to do that, please help me :)!
Run app class :
import javax.swing.JFrame;
public class RunApp {
public static void main(String[] args) {
JFrame mainFrame = new MyPanel();
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
mainFrame.setVisible(true);
}
}
MyPanel class :
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MyPanel extends JFrame {
private JPanel leftPanel = null;
private JPanel rightPanel = null;
private JPanel mainPanel = null;
private JButton start = null;
private JButton restart = null;
private JComboBox<String> menuBox = new JComboBox<>();
private Toolkit kit = Toolkit.getDefaultToolkit();
private Dimension screenSize = kit.getScreenSize();
private int screenHeight = screenSize.height;
private int screenWidth = screenSize.width;
public MyPanel() {
mainPanel = new JPanel();
mainPanel.setBackground(Color.orange);
mainPanel.setPreferredSize(getPreferredSize());
leftPanel = new JPanel();
leftPanel.setBackground(Color.blue);
leftPanel.setPreferredSize(new Dimension(screenWidth/6, screenHeight));
menuBox.addItem("Gaussian Wave - non Dispersive");
menuBox.addItem("Gaussian Wave - Dispersive");
start = new JButton("Start");
restart = new JButton("Restart");
leftPanel.add(menuBox);
leftPanel.add(start);
leftPanel.add(restart);
rightPanel = new JPanel();
rightPanel.setBackground(Color.red);
rightPanel.setPreferredSize(new Dimension(screenWidth -( screenWidth/5 ), screenHeight));
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(menuBox.getItemAt(menuBox.getSelectedIndex()).equals("Gaussian Wave - non Dispersive")) {
rightPanel.add(new MyComponent());
rightPanel.revalidate();
rightPanel.repaint();
} else if(menuBox.getItemAt(menuBox.getSelectedIndex()).equals("Gaussian Wave - Dispersive")) {
rightPanel.add(new MyComponent());
rightPanel.revalidate();
rightPanel.repaint();
}
}
});
restart.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
rightPanel.removeAll();
rightPanel.revalidate();
rightPanel.repaint();
rightPanel.setBackground(Color.RED);
}
});
mainPanel.add(leftPanel);
mainPanel.add(rightPanel);
add(mainPanel);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(screenWidth, screenHeight);
}
}
Like i say the MyComponent class is not working when i add it in this way. Normally when i add this class directly like :
public MyPanel() {
add(new MyComponent);
}
Working perfect, but i want to add it after choose from the list to the divided screen. Thx !
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.GeneralPath;
import java.util.function.Function;
import javax.swing.JComponent;
public class MyComponent extends JComponent {
private int wx, wy;
private double xMin, xMax, yMin, yMax, xInc, time;
private Function<Double, Double>gaussFunction;
private Function<Double, Double>dispersiveGaussFunction;
public MyComponent() {
init();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
makeGraphics(g2);
}
private void makeGraphics(Graphics2D g2) {
GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
if(time < 5) {
countGaussianWave(this.time);
double x = xMin;
double y = gaussFunction.apply(x);
path.moveTo(
mapX(x), mapY(y)
);
x+=xInc;
while(x < xMax) {
y = gaussFunction.apply(x);
path.lineTo(
mapX(x), mapY(y)
);
x+=xInc;
}
g2.draw(path);
repaint();
this.time+=0.001;
if(this.time > 3.5) {
this.time = -3.5;
System.out.println(time);
}
}
}
private void init() {
wx = 700;
wy = 700;
xMin = -1;
xMax = 1;
yMin = -1;
yMax = 1;
xInc = 0.01;
setTime(time);
}
private double mapX(double x) {
double fx = wx / 2;
double sx = wx / (xMax - xMin);
return x * fx + sx;
}
private double mapY(double y) {
double fy = wy / 2;
double sy = wy / (yMax - yMin);
return -y * sy + fy;
}
public void countGaussianWave(double time) {
double lambda = 1;
this.gaussFunction = x -> {
return x = Math.exp(-(Math.pow((x-time ), 2)))
* (Math.cos((2*Math.PI*(x-time))/lambda)
+ Math.sin((2*Math.PI*(x-time))/lambda)); // need complex
};
}
// public void countDispersiveGaussianWave(double time) {
//
// double lambda = 1;
// double k = (2 * Math.PI) / lambda;
//
// this.dispersiveGaussFunction = x -> {
// return x = (1/(Math.sqrt(1 + 2 * time)) *
// Math.exp(-(Math.pow((1 / Math.pow(1 + 4 * time, 2)) * (x - k * time), 2)))
// * Math.exp(Math.pow(, b));
// );
// };
// }
public double getTime() {
return time;
}
public void setTime(double time) {
this.time = time;
}
}
app ss
Don't use "==" when comparing objects.
Instead you should be using the equals(...) method.
When you add (or remove) a component to a visible GUI the basic code is:
panel.add(...);
panel.revalidate();
panel.repaint();
Basically you need to make sure the layout manager is invoked otherwise the component has a size of (0, 0) so there is nothing to paint.
Also, you need to override the getPreferredSize() method to return the size of the component. Otherwise the size is (0, 0) so there is nothing to paint.
Edit
I'm guessing your components isn't showing because of your poor GUI design and hardcoding of values. A FlowLayout is a terrible layout to use for ALL the components added to the frame. You need to make an effort to logically organize the components on panels with appropriate layout managers. When lots of components are added the components will wrap to a second row. However, the preferred size does not automatically change so you may not see all the components. So
rightPanel.setPreferredSize(new Dimension(...) );
Don't hardcode a preferred size. Each component is responsible for determining its own size which is why you override the getPreferredSize() method. Then the layout manages can do their job properly. So get rid of all the setPreferrededSize() statements.
The default layout for a Jframe is a BorderLayout. I would stick with that layout. There is no need for your mainPanel as the content pane for the frame is already a JPanel.
So I would rename your "leftPanel" and maybe call it "topPanel". Then you can just add the fixed components to that panel and add that panel to the frame:
JPanel topPanel = new JPanel();
topPanel.add( comboBox );
topPanel.add( startButton );
topPanel.add( restartButton );
frame.add(topPanel, BorderLayout.PAGE_START);
So these components will appear at the top of the frame.
Now there is also no need for the "rightPanel". Instead you can just add your component directly to the frame.
frame.add( new MyComponent(), BorderLayout.CENTER);
frame.revalidate();
frame.repaint();
This component will now appear in the center of the frame and take up all the extra space available in the frame.
To start, you can simplify the start buttons ActionListener logic like so
if(combobox.getSelectedItem().equals("Text")
{
doSomething();
}
Also, after adding or removing new components, you need to call Revalidate & Repaint
If you're trying to paint in one of the components, make sure to #Override it and call it's super method super.paintComponent(g);
You also have 2 action listeners assigned to the same button. I suggest removing one of those
Along with #Camickr's answer of Overriding the getPreferredSize() method, you should change the restart button's ActionListener to this
rightPanel.removeAll();
rightPanel.revalidate();
rightPanel.repaint();
rightPanel.setBackground(Color.RED);
You can Override the getPreferredSize(); method like so:
#Override
public Dimension getPreferredSize()
{
int width = Toolkit.getDefaultToolkit().getScreenSize().width / 2;
int height = Toolkit.getDefaultToolkit().getScreenSize().height;
return new Dimension(width, height);
}

Transparent JFrame with draggable components [duplicate]

This question already has answers here:
Animation on Transparent-background JFrame Linux
(3 answers)
Closed 7 years ago.
I want to create a hud-like ui by using draggable JComponents on a transparent background. Minimal example of what I have so far:
import java.awt.Color;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class TransparentFrame
extends JFrame {
public TransparentFrame() {
setLayout(null);
setUndecorated(true);
setBackground(new Color(1, 1, 1, 0.0f));
setLocationRelativeTo(null);
setSize(600, 500);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JLabel label = new JLabel("ABC");
label.setBounds(100, 100, 60, 30);
label.setOpaque(true);
label.setBackground(Color.RED);
label.setForeground(Color.WHITE);
DraggableComponentListener listener = new DraggableComponentListener(label);
label.addMouseListener(listener);
label.addMouseMotionListener(listener);
add(label);
setVisible(true);
}
public static void main(String[] args) {
new TransparentFrame();
}
}
class DraggableComponentListener
extends MouseAdapter {
private Component component;
private volatile int screenX = 0;
private volatile int screenY = 0;
private volatile int componentX = 0;
private volatile int componentY = 0;
public DraggableComponentListener(Component component) {
this.component = component;
}
#Override
public void mousePressed(MouseEvent e) {
screenX = e.getXOnScreen();
screenY = e.getYOnScreen();
componentX = component.getX();
componentY = component.getY();
}
#Override
public void mouseDragged(MouseEvent e) {
int deltaX = e.getXOnScreen() - screenX;
int deltaY = e.getYOnScreen() - screenY;
component.setLocation(componentX + deltaX, componentY + deltaY);
}
}
When the label is dragged, it leaves traces behind: it is painted at all positions it has been at. I tried adding the label to a JPanel, the panel to the frame and overriding the panel's paintComponent method as described here: https://tips4java.wordpress.com/2009/05/31/backgrounds-with-transparency/, the result was the same.
Any suggestions?
Unfortunately, it is working properly on my machine (doesn't leave any traces). Try adding a frame.repaint() after the location changed of the component. Use the repaint variation that takes the paint area for performance.

KeyPressed and mousePressed Event in an unfocused Component

What are several ways of detecting a key stroke without the need of focusing on the component that the event was implemented? Here's my idea on this:
Even without focusing on myComponent, upon pressing a key, the action should take part. ** Same question for the mousePressed event. A mouse click will be detected even when not clicking on the component.**
myComponent.addKeyListener( new KeyAdapter() {
#Override
public void keyPressed( KeyEvent e ){
// My action here
}
});
Upon answering Question1, can it also be done even if the application is running on background? Say I have a browser, every time I click or press a key, the given action will be executed.
I also accept suggestions to read as an answer. If your answer would be KeyBinding related, please do elaborate. All answer and comments will be greatly appreciated.
I used JNativeHooks examples here and it works perfectly fine. Any other method by just Java alone?
For the first question, regarding the KeyStroke thingy, I guess you can use KeyBinding instead of using KeyListener, that can give you the desired result, without the focus related issues of the component in question, though within the Java Dimensions.
In the example below, the focus is on the JTextField first, so if you will Press CTRL + D, then the paintAction thingy attached to the CustomPanel will work, even though the focus lies with the JTextField.
Though if you will use the setMnemonic() method for JButton, then the JButton will gain focus and will perform it's own action associated with it, which is to draw Ovals. This you can see by Pressing ALT + C, to see the desired effect. Again to perform the drawing related thingy, both the components in question don't need the focus, but still they respond to the KeyStrokes.
Here is the example code :
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class SSCCE
{
private final int WIDTH = 500;
private final int HEIGHT = 500;
private CustomPanel customPanel;
private JButton circleButton;
private JTextField tfield;
private Random random;
private int mode;
private Action paintAction = new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent ae)
{
mode = random.nextInt(3);
Color color = new Color(random.nextFloat(), random.nextFloat()
, random.nextFloat(), random.nextFloat());
customPanel.setValues(random.nextInt(WIDTH),
random.nextInt(HEIGHT), random.nextInt(WIDTH),
random.nextInt(HEIGHT), color, mode);
}
};
private ActionListener buttonAction = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent ae)
{
Color color = new Color(random.nextFloat(), random.nextFloat()
, random.nextFloat(), random.nextFloat());
customPanel.setValues(random.nextInt(WIDTH),
random.nextInt(HEIGHT), random.nextInt(WIDTH),
random.nextInt(HEIGHT), color, 2);
}
};
public SSCCE()
{
random = new Random();
}
private void displayGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout(5, 5));
customPanel = new CustomPanel();
customPanel.getInputMap(
JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke(KeyEvent.VK_D
, InputEvent.CTRL_DOWN_MASK), "paintAction");
customPanel.getActionMap().put("paintAction", paintAction);
JPanel footerPanel = new JPanel();
circleButton = new JButton("Draw Circle");
circleButton.setMnemonic(KeyEvent.VK_C);
circleButton.addActionListener(buttonAction);
tfield = new JTextField(20);
tfield.setText("USELESS, just to get the focus for itself.");
tfield.requestFocusInWindow();
footerPanel.add(tfield);
footerPanel.add(circleButton);
contentPane.add(customPanel, BorderLayout.CENTER);
contentPane.add(footerPanel, BorderLayout.PAGE_END);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String... args)
{
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
new SSCCE().displayGUI();
}
});
}
}
class CustomPanel extends JPanel
{
private final int WIDTH = 500;
private final int HEIGHT = 500;
private int mode = 0;
private Color colorShape;
private int x = 0;
private int y = 0;
private int width = 0;
private int height = 0;
public void setValues(int x, int y, int w, int h, Color color, int mode)
{
this.x = x;
this.y = y;
this.width = w;
this.height = h;
this.colorShape = color;
this.mode = mode;
repaint();
}
#Override
public Dimension getPreferredSize()
{
return (new Dimension(WIDTH, HEIGHT));
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(colorShape);
if (mode == 1)
g.fillRect(x, y, width, height);
else if (mode == 2)
g.fillOval(x, y, width, height);
}
}
Related to mousePressed() thingy, #mKorbel, had presented the whole thingy as usual in a delightful manner.
And regarding your second question, seems like you yourself had done some homework on that. Seems like either using what you showed in your question is the workaround for catching Operating System related events and transfer that to your Java Application or Java Native Interface, I guess might also can work for this.
all JComponent has method dispatchEvent,
you can to redirect mouse & key event from one JComponent to the another
for JButton to use doClick() instead
for example
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class LostMouseEvent {
private JPanel panel1;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new LostMouseEvent();
}
});
}
public LostMouseEvent() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
panel1 = new JPanel() {
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredSize() {
return new Dimension(600, 400);
}
};
JPanel panel2 = new JPanel() {
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 300);
}
};
JScrollPane pane = new JScrollPane(panel2);
panel1.setBorder(BorderFactory.createLineBorder(Color.blue));
panel2.setBorder(BorderFactory.createLineBorder(Color.green));
panel1.setLayout(new CircleLayout());
panel1.add(pane);
frame.add(panel1);
MouseListener rml = new RealMouseListener();
panel1.addMouseListener(rml);
MouseListener fml = new FakeMouseListener();
panel2.addMouseListener(fml);
frame.pack();
frame.setVisible(true);
}
});
}
private class RealMouseListener extends MouseAdapter {
#Override
public void mousePressed(MouseEvent me) {
System.out.println(me);
Point point = me.getPoint();
System.out.println(me.getX());
System.out.println(me.getXOnScreen());
System.out.println(me.getY());
System.out.println(me.getYOnScreen());
}
}
private class FakeMouseListener extends MouseAdapter {
#Override
public void mousePressed(MouseEvent me) {
JPanel panel2 = (JPanel) me.getSource();
MouseEvent newMe = SwingUtilities.convertMouseEvent(panel2, me, panel1);
System.out.println(newMe.getX());
System.out.println(newMe.getXOnScreen());
System.out.println(newMe.getY());
System.out.println(newMe.getYOnScreen());
panel1.dispatchEvent(me);
}
}
}

How do I order two components in a JFrame in order for transparency and ActionListeners to work?

When adding two components to a JFrame, where one sits inside another, If I add them in the order, Fullscreen Object, then JPanel, the JPanel displays correctly, but is essentially invisible, i.e it's action listener won't work and the clicks register on the fullscreen object. If I add them the other way round The JPanel works as it should, but doesn't display correctly (It has transparent areas).
This is the code for the Frame I am adding the components to.
gameOBJ = new gameClass(width, height);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(0);
frame.add(gameOBJ.UIPanel);
frame.add(gameOBJ);
frame.validate();
frame.setUndecorated(true);
frame.setBounds(0, 0, width, height);
frame.setResizable(false);
frame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent we)
{
new exitWindow("Don't forget to save your game! \n Are you sure you want to Exit?", true);
}
});
frame.setVisible(true);
gameOBJ.start();
Here is the code for the JPanel (Stripped down for simplicity's sake)
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
public class UserInterface extends JPanel implements ActionListener
{
private static final long serialVersionUID = 1L;
private Image image;
private int xBound = 800;
private int yBound = 177;
private JButton mainMenuButton = new JButton(new ImageIcon("res/images/MainMenuButton.gif"));
private int buttonWidth = 179;
private int buttonHeight = 52;
public UserInterface()
{
this.setLayout(null);
this.image = new ImageIcon("res/images/UIPanelImage.gif").getImage();
this.setOpaque(false);
this.setSize(this.xBound, this.yBound);
mainThreeButtons(); //ONLY ONE SHOWN FOR SIMPLICITY
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image, 0, 0, this); //IMAGE CONTAINS TRANSPARENCY
}
#Override
public void actionPerformed(ActionEvent event)
{
else if (event.getSource() == mainMenuButton)
{
new mainMenuWindow();
}
}
private void mainThreeButtons()
{
this.add(mainMenuButton);
mainMenuButton.addActionListener(this);
//mainMenuButton.setOpaque(false);
mainMenuButton.setBorderPainted(false);
mainMenuButton.setContentAreaFilled(false);
mainMenuButton.setBounds(617, 6, buttonWidth, buttonHeight);
}
}
I would show an image but I'm not allowed to, The area which is meant to be transparent isn't showing the frame, because it is grey, whatever I set as the Frame's background, OR the panel's background, as again it is grey whatever I set the panel's background colour as.
You probably want to use JLabel instead of JPanel. I know it sounds a bit unintuitive, but I'm not sure JPanel is suited to the purpose you are using it for. Also, JLabel can have a native ImageIcon set, so try using that.
public UserInterface() { // extends JLabel
this.setImageIcon(new ImageIcon("res/images/UIPanelImage.gif"));
// or super(~imageicon~)
}
Unlikely, but it could be that the image is not yet loaded when it gets drawn. You should use MediaTracker to manage that more carefully (although I'm not sure ImageIcon if takes care of this for you).
final static protected MediaTracker mediatracker = new MediaTracker(new Canvas());
static protected void checkImageIsReady(Image i) {
mediatracker.addImage(i, 1);
try {
mediatracker.waitForAll();
} catch (InterruptedException e) { }
mediatracker.removeImage(i);
}

Categories

Resources