I has a MouseAdapter that I use to drag a window around simply by clicking its background, like so:
public class Dragger extends MouseAdapter{
private Point offset;
private Window window;
public Dragger(Window w){
window = w;
}
#Override
public void mousePressed(MouseEvent e){
offset = e.getPoint();
}
#Override
public void mouseDragged(MouseEvent e){
Point m = e.getLocationOnScreen();
window.setLocation(m.x - offset.x, m.y - offset.y);
}
}
Simple as, right?
And I add it to the JFrame I'm using it on (I'm using it on a JDialogUE as well, hence the 'Window':
// Drag Listeners
Dragger dr = new Dragger(this);
addMouseListener(dr);
addMouseMotionListener(dr);
The drag (currently) only works when I construct a new Dragger, then add it as both a MouseListener and MouseMotionListener.
Is there a nicer, prettier, more elegant, more traditionally sound, more professionally robust, so it goes, way of doing it in just one method?
In such cases I would suggest writing helper static methods within the Dragger class:
public class Dragger extends MouseAdapter
{
private Point offset;
private Window window;
public Dragger ( final Window w )
{
window = w;
}
#Override
public void mousePressed ( final MouseEvent e )
{
offset = e.getPoint ();
}
#Override
public void mouseDragged ( final MouseEvent e )
{
final Point m = e.getLocationOnScreen ();
window.setLocation ( m.x - offset.x, m.y - offset.y );
}
public static void install ( final Window window )
{
final Dragger dr = new Dragger ( window );
window.addMouseListener ( dr );
window.addMouseMotionListener ( dr );
}
public static void uninstall ( final Window window )
{
for ( final MouseListener mouseListener : window.getMouseListeners () )
{
if ( mouseListener instanceof Dragger )
{
window.removeMouseListener ( mouseListener );
}
}
for ( final MouseMotionListener mouseMotionListener : window.getMouseMotionListeners () )
{
if ( mouseMotionListener instanceof Dragger )
{
window.removeMouseMotionListener ( mouseMotionListener );
}
}
}
}
And then simply call Dragger.install(window) and Dragger.uninstall(window).
Not sure whether it is a good approach or not, but it takes less space and might also ensure that you don't add Dragger twice if you add some more checks into install method - of course if you don't want to have Dragger installed twice on the same window.
Also in that case you don't need to look in your code for the usage of this class since you are sure how it will be installed and uninstalled and can change that behavior in one place instead of modifying lots of add*Listener calls.
Related
I am trying to implement a listener to detect the closing of a window. My main class is extending other classes so I am unable to extend JFrame which is not allowing me to use addWindowListener.
I have tried the code below but it is not working.
public class PowerPanel extends AnotherPanel implements ActionListener, PropertyChangeListener {
// logic …
this.addWindowListener(new WindowAdapter() {
public void windowClosing (WindowEvent e ) {
// do things
}
});
}
The error I am getting is indicating that addWindowListener is "undefined for the type PowerPanel."
You can't add window listener to your panel - you need to add it into the java.awt.Window instance which in your case is a JFrame.
If it is hard for you to pass your JFrame instance into the panel - you can access it in a different way:
public class SamplePanel extends JPanel
{
/**
* Simple panel example that has no idea about it's parent window.
*/
public SamplePanel ()
{
super ();
// Your custom window listener
final WindowAdapter windowAdapter = new WindowAdapter ()
{
#Override
public void windowClosing ( final WindowEvent e )
{
System.out.println ( "Window is closing" );
}
};
// Ancestor availability listener
// It will make sure that whenever component appears on some visible window
// and is displayable container - we will add our window listener to it
addAncestorListener ( new AncestorAdapter ()
{
/**
* Saved window to remove listener from later on.
*/
private Window window = null;
#Override
public void ancestorAdded ( final AncestorEvent event )
{
// Component appeared on some window, we can add our listener now
addListener ();
}
#Override
public void ancestorMoved ( final AncestorEvent event )
{
// Re-adding listener to potentially new parent window
removeListener ();
addListener ();
}
#Override
public void ancestorRemoved ( final AncestorEvent event )
{
// Component was hidden or removed, we need to remove our listener
removeListener ();
}
/**
* Adds window listener.
*/
protected void addListener ()
{
window = SwingUtilities.getWindowAncestor ( SamplePanel.this );
if ( window != null )
{
window.addWindowListener ( windowAdapter );
}
}
/**
* Removes window listener.
*/
protected void removeListener ()
{
if ( window != null )
{
window.removeWindowListener ( windowAdapter );
window = null;
}
}
} );
}
/**
* Sample main method for runing the example.
*
* #param args arguments
*/
public static void main ( final String[] args )
{
SwingUtilities.invokeLater ( new Runnable ()
{
#Override
public void run ()
{
final JFrame frame = new JFrame ();
final SamplePanel panel = new SamplePanel ();
panel.add ( new JLabel ( "Sample panel content" ) );
frame.add ( panel );
frame.pack ();
frame.setDefaultCloseOperation ( JFrame.DISPOSE_ON_CLOSE );
frame.setLocationRelativeTo ( null );
frame.setVisible ( true );
}
} );
}
}
With this code your panel will automatically register window listener on it's parent window whenever it is displayed. It will also automatically remove the listener once panel is hidden or removed from the window, so potentially this is the best solution you can have.
Be careful though, if you will use that panel multiple times on the same window - all of the instances will add their own listener and will all perform on-close action separately. If you want to perform your on-close operation just once per window/frame/dialog instance - you need to add the listener on the window itself, preferably where it is created not to make it obscure.
You might also notice that in my example there is actually a method that retrieves panel's parent window directly:
window = SwingUtilities.getWindowAncestor ( SamplePanel.this );
Although you can't use it in your panel directly, because at the moment when panel is created it is not yet added into any container, let alone visible window. That is why the solution with ancestor listener that i've shown is required.
I am making an apllication in java swing for practice by using drag and drop components , i am facing a problem, i put inside the JPanel, an JInternal Frame
, it is moveable,
i want to make it un-moveable
,which event is used for it? How can i do it ? i search on the internet but unfortunately unable to find the solution for this.
I have found this on internet but i want to do it with the help of event option in swing.
// Make first internal frame unmovable
JInternalFrame[] frames = frame.desktop.getAllFrames();
JInternalFrame f = frames[0];
BasicInternalFrameUI ui = (BasicInternalFrameUI)f.getUI();
Component north = ui.getNorthPane();
MouseMotionListener[] actions = // there is no option for MouseMotionListener in the event option
(MouseMotionListener[])north.getListeners(MouseMotionListener.class);
for (int i = 0; i < actions.length; i++)
north.removeMouseMotionListener( actions[i] );
DesktopManager is resposible for all operation with internal frames. So you can redefine it using the proxy pattern to make some of your frames non-movable. Here is non-complete example for you (sorry I havn't tested this code, so I'm not sure whether it works).
private static class ProxyDesktopManager implements DesktopManager {
private final DesktopManager delegate;
public ProxyDesktopManager(DesktopManager delegate) {
this.delegate = Objects.requireNonNull(delegate);
}
// Check whether frame is moveable
private boolean checkFrameMovable(JComponent frame) {
if (frame instanceof JInternalFrame) {
// TODO check whether the frame if movable
}
return false;
}
#Override
public void beginDraggingFrame(JComponent f) {
if (checkFrameMovable(f)) {
delegate.beginDraggingFrame(f);
}
}
#Override
public void dragFrame(JComponent f, int newX, int newY) {
if (checkFrameMovable(f)) {
delegate.dragFrame(f, newX, newY);
}
}
#Override
public void endDraggingFrame(JComponent f) {
if (checkFrameMovable(f)) {
delegate.endDraggingFrame(f);
}
}
#Override
public void openFrame(JInternalFrame f) {
delegate.openFrame(f);
}
#Override
public void closeFrame(JInternalFrame f) {
delegate.closeFrame(f);
}
#Override
public void maximizeFrame(JInternalFrame f) {
delegate.maximizeFrame(f);
}
#Override
public void resizeFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) {
delegate.resizeFrame(f, newX, newY, newWidth, newHeight);
}
// IMPORTANT: simply delegate all another methods like openFrame or
// resizeFrame
}
Now you can use this proxy class for your JDesktopPane
JDesktopPane desktop = new JDesktopPane();
desktop.setDesktopManager(new ProxyDesktopManager(desktop.getDesktopManager()));
I have a code that has a JLabel which follows the mouse. The JLabel says "exit" whenever the user exits the window, and stays at the last position the user was in. The problem is, the "exit" is only visible at when exiting the window from the top. This is because the JLabel is under the mouse. I want to make it so that the label moves down so I can see it if it exits up and move up if it exits down. I understand how to move it, but can we move it based on conditions? It shows up in the window fine, I just need to position it on different sides of my mouse based on exit position.
Here is my code:
class giraffemousehandler extends MouseAdapter implements MouseListener, MouseMotionListener { //MouseAdapter makes it so that you don't have to have all 7 implemented mouse listener methods
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
status.setBounds(e.getX(), e.getY(), 50, 60); //Makes JLabel follow mouse
}
#Override
public void mouseEntered(MouseEvent e) {
status.setText("Entered");
}
#Override
public void mouseExited(MouseEvent e) {
status.setText("exited");
// status.setBounds(e.getX(), e.getY(), 5, 6);
}
}
}
Thank you so much for the time you are taking for reading this, I really appreciate the effort you are putting into helping a fellow programmer!
public class GiraffeMouseHandler extends MouseAdapter implements MouseMotionListener
{
public void mouseEntered( MouseEvent event )
{
status.setText( "Entered" );
}
public void mouseExited( MouseEvent event )
{
status.setText( "Exited" );
}
public void mouseMoved( MouseEvent event )
{
//dimension is a reference of dimension of the main frame
if( ( dimension.getHeight() - event.getY() ) < 65 )
status.setBounds( event.getX(), (int)dimension.getHeight() - 65 , 50, 60 );
else if( ( dimension.getWidth() - event.getX() ) < 50 )
status.setBounds( (int)dimension.getWidth() - 50, event.getY(), 50, 60 );
else
status.setBounds( event.getX(), event.getY(), 50, 60 );
}
}
I'm starting to teach myself Java, and it's possible my reach doth exceed my grasp. Still, that's the best way to learn, right?
I'm trying to play around with simple graphics. I've found various resources on how to draw shapes into a JFrame, and made them work, but as far as I can tell the code always needs to go inside the paint method, which gets called automatically, which means I can't figure out how to go about passing it arguments.
What I'm trying to do is write some code that can take co-ordinates as arguments, and then place a simple shape (let's go with a 10x10 pixel square) at those co-ordinates. I feel sure that must be something that's possible, but I cannot for the life of me work out how.
Code so far, incorporating help from both #resueman and #Mikle:
public class Robots {
public static void main(String[] args) {
Window window = new Window();
window.Window();
new PlayArea();
Point p = new Point(50,50);
Entity player1 = new Entity();
player1.Entity(p);
}
}
public class Window extends JFrame{
int x;
int y;
public void Window(){
Window window = new Window();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setTitle("Robots");
window.setSize(800,600);
window.getContentPane().add(new PlayArea());
window.setLocationRelativeTo(null);
window.setBackground(Color.white);
window.setVisible(true);
}
}
public class PlayArea extends JComponent{
// I keep all added and displayed entities here for easier access
public final List<Entity> entities = new ArrayList<Entity> ();
public PlayArea(){
super();
}
public void addEntity(final Entity entity){
//add new entity and repaint area
entities.add(entity);
}
#Override
protected void paintComponent (final Graphics g)
{
super.paintComponent (g);
// Painting entities
final Graphics2D g2d = (Graphics2D) g;
for (final Entity entity : entities)
{
g2d.setPaint ( Color.BLACK );
g2d.fill (getEntityShape (entity));
}
}
protected Shape getEntityShape ( final Entity entity )
{
// Simple entity shape, you can replace it with any other shape
return new Rectangle ( entity.entPos.x - 5, entity.entPos.y - 5, 10, 10 );
}
}
public class Entity extends JComponent{
protected Point entPos = null;
public void Entity(Point p){
entPos = p;
repaint();
}
#Override
public void paintComponent (Graphics g){
super.paintComponent(g);
if (entPos != null){
g.fillRect(entPos.x, entPos.y, 10,10);
}
}
}
I want to be able to create an object in the Entity class, and put it in the window at the x,y co-ordinates.
I will eventually want to be able to move Entities around, but I'll work that one out once I've figured out how to draw them in the first place!
Still not drawing anything in the window. I'm probably missing something really obvious though.
There are a lot of possible approaches to solve your task.
Here are the first two options which come to mind:
Use a custom component and paint all Entity objects in it
This one will be easy and fast to implement.
Implementing entities drag also won't be a big issue. There are also a few options how painting can be done here. This approach is good in case you are going to have just a few simple elements painted on the area and don't want to make your code too complicated.
Paint each Entity on a separate component, and place them using layout managers
This is harder to achieve, but it will use much less resources and will be painted faster due to Swing repainting optimizations. This approach is much better if you are aiming at a large amount of elements or large area size. But that might be an overkill for your case.
Here is a simple example of the 1st approach (including entities drag):
public class SingleComponent extends JFrame
{
public SingleComponent () throws HeadlessException
{
super ();
setTitle ( "Robots" );
setBackground ( Color.white );
// Adding our custom component into the frame
getContentPane ().add ( new EntitiesArea () );
setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
setSize ( 800, 600 );
setLocationRelativeTo ( null );
setVisible ( true );
}
public class Entity
{
int x;
int y;
public Entity ( final int x, final int y )
{
this.x = x;
this.y = y;
}
}
public class EntitiesArea extends JComponent
{
// I keep all added and displayed entities here for easier access
public final List<Entity> entities = new ArrayList<Entity> ();
public EntitiesArea ()
{
super ();
// Adding mouse adapter that will add/drag entities
final MouseAdapter mouseAdapter = new MouseAdapter ()
{
// Currently dragged entity
private Entity dragged = null;
#Override
public void mousePressed ( final MouseEvent e )
{
// Looking for entity under mouse
Entity underPoint = null;
for ( final Entity entity : entities )
{
if ( getEntityShape ( entity ).contains ( e.getPoint () ) )
{
underPoint = entity;
break;
}
}
// Either dragging existing entity or adding new one
if ( underPoint != null )
{
dragged = underPoint;
}
else
{
addEntity ( new Entity ( e.getX (), e.getY () ) );
}
}
#Override
public void mouseDragged ( final MouseEvent e )
{
if ( dragged != null )
{
// Change entity coordinate and repaint area
dragged.x = e.getX ();
dragged.y = e.getY ();
repaint ();
}
}
#Override
public void mouseReleased ( final MouseEvent e )
{
if ( dragged != null )
{
dragged = null;
}
}
};
addMouseListener ( mouseAdapter );
addMouseMotionListener ( mouseAdapter );
}
public void addEntity ( final Entity entity )
{
// Add new entity and repaint area
entities.add ( entity );
repaint ();
}
#Override
protected void paintComponent ( final Graphics g )
{
super.paintComponent ( g );
// Painting entities
final Graphics2D g2d = ( Graphics2D ) g;
for ( final Entity entity : entities )
{
g2d.setPaint ( Color.BLACK );
g2d.fill ( getEntityShape ( entity ) );
}
}
protected Shape getEntityShape ( final Entity entity )
{
// Simple entity shape, you can replace it with any other shape
return new Rectangle ( entity.x - 20, entity.y - 20, 40, 40 );
}
}
public static void main ( final String[] args )
{
new SingleComponent ();
}
}
I didn't add any repaint optimizations to this example to make it as simple as it could be, but keep in mind that any action in this example repaints the whole area and forces each entity to be painted from a scratch. This won't even be noticeable until a large amount of elements appear on the area, but make sure you take care of optimized repaint(...) calls later as this is one of the things that make Swing so fast and so good.
If you want to draw independently of the presentation / rendering, you can draw on a BufferedImage for example. You can acquire a Graphics object associated with the BufferedImage with its getGraphics() and createGraphics() methods.
And if later you want to display this, you can with the Graphics.drawImage() methods inside JComponent.paintComponent().
using Eclipse to make java Applet. Every time to run it from the IDE, the applet viewer is shown on left top corner at (0,0). How to programmably change it to the middle of screen during the development? I know when deploy in browser, we can't change the window from inside the applet since the html determines the location.
In contrast to the other poster, I think this is a pointless exercise and prefer their suggestion to make an hybrid application/applet to make development easier.
OTOH - 'we have the technology'. The top-level container of an applet in applet viewer is generally a Window. Get a reference to that, and you can set it where you wish.
Try this (irritating) little example.
// <applet code=CantCatchMe width=100 height=100></applet>
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Random;
public class CantCatchMe extends JApplet {
Window window;
Dimension screenSize;
JPanel gui;
Random r = new Random();
public void init() {
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
moveAppletViewer();
}
};
gui = new JPanel();
gui.setBackground(Color.YELLOW);
add(gui);
screenSize = Toolkit.getDefaultToolkit().getScreenSize();
// change 2000 (every 2 secs.) to 200 (5 times a second) for REALLY irritating!
Timer timer = new Timer(2000, al);
timer.start();
}
public void start() {
Container c = gui.getParent();
while (c.getParent()!=null) {
c = c.getParent();
}
if (c instanceof Window) {
window = (Window)c;
} else {
System.out.println(c);
}
}
private void moveAppletViewer() {
if (window!=null) {
int x = r.nextInt((int)screenSize.getWidth());
int y = r.nextInt((int)screenSize.getHeight());
window.setLocation(x,y);
}
}
}
Interesting question.
I've not found a reliable way to influence AppletViewer, not without using a script on Windows to start it from a batch file mode, and even that didn't work too well.
The alternative is to write your test code so the Applet starts in a JFrame, which you can easily center.
Add a main method to your Applet :
public class TheApplet extends JApplet {
int width, height;
public void init() {
width = getSize().width;
height = getSize().height;
setBackground( Color.black );
}
public void paint( Graphics g ) {
g.setColor( Color.orange );
for ( int i = 0; i < 10; ++i ) {
g.drawLine( width / 2, height / 2, i * width / 10, 0 );
}
}
public static void main(String args[]) {
TheApplet applet = new TheApplet();
JFrame frame = new JFrame("Your Test Applet");
frame.getContentPane().add(applet);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(640,480);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
applet.init();
}
}
This should work, unless I missed something - I updated it work code I have running on my machine.