I'm working on a complex java swing project.
during initialization I set the frame size to 1280X1024.
sometimes when I launch my app the frame starts with the expected dimensions
other times the frame actual size is 1282X1053 (always this size).
I have two question, while trying to pinpoint the source for this issue.
1) is there a way to set a watch point when the frame size is changed?
I'm using eclipse, and when I tried to set a watch point, it breaks when every component I have changes size. this is unacceptable as I have too many components to manually follow.
2) due to the fact that the issue doesn't reproduce every time, I'm worried that maybe somewhere in the code I access Java swing component outside the EDT. is there a way to verify that all the calls to all the swing components in my code are done from the EDT?
EDIT:
the below code is a sample of what I use.
I can't attach the code to build the panels as it is too complex to fit here
EDIT 2: the code below works. the problem is happens because of the commented lines before calling setVisible
package com.earlysense.nursestation;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MyFrame extends JFrame {
private JPanel west;
private JPanel center;
/**
* Initializes the panels
*/
public void init() {
setLocation(0, 0);
setPreferredSize(new Dimension(1280, 1024));
setUndecorated(true); // The frame is fixed. It cannot be moved or resized.
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p = new JPanel(new BorderLayout());
west = new JPanel();
west.add(new JLabel("west"));
center = new JPanel();
center.add(new JLabel("center"));
p.add(BorderLayout.WEST, west);
p.add(BorderLayout.CENTER, center);
getContentPane().add(p);
}
public static void main(String[] args) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
MyFrame frame = new MyFrame();
frame.init();
frame.pack();
// at this point frame.getSize() returns 1280X1024
// add components to west and center panel which depends on the frame size to set self size
frame.setVisible(true);
// at this point frame.getSize() sometimes returns 1282X1053
}
});
} catch (InterruptedException e) {/* Do nothing */
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
It seems like a bug in java.
was known in java 1.3, but apparently still happens. I'm using ubuntu 13.10 64bit, jdk: OpenJDK Runtime Environment (IcedTea6 1.12.6) (6b27-1.12.6-1ubuntu2.1)
link
I set the frame size to 1280X1024.
Why? My screen is 1024 x 768, so I guess I can't use your application? Don't hardcode values. Instead use:
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
SwingUtilities.invokeAndWait(new Runnable() {
Why are you using invokdeAndWait? All the Swing tutorial and suggestions by people in the forum use invokeLater(..).
Related
Maybe i have encountered a bug or more probably doing something wrong ;)
I try to translate the content of a user drawn JPanel using a JScrollPanel. Inside the panel the drawing i would like to access the visible area through the Graphics class getClipBounds method to improve rendering performance.
Searching on SO brings a lot results referring to JScrollPane but none is mentioning a problem with the clip bounds. Google the same.
user drawn panel
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Content extends JPanel {
#Override
protected void paintChildren(Graphics g) {
super.paintChildren(g);
// intense clip bounds dependent rendering here
System.out.println(g.getClipBounds());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(2000,2000);
}
}
main frame setup
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
public class ClipBoundsIssue {
private JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ClipBoundsIssue window = new ClipBoundsIssue();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public ClipBoundsIssue() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JScrollPane scrollPane = new JScrollPane();
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
Content content = new Content();
scrollPane.setViewportView(content);
}
}
to reproduce
Just run the code, move one of the scrollbars and inspect the console output of System.out. The following picture depicted scrolling the bar on the x axis.
actual System.out result
Which produced the following results
java.awt.Rectangle[x=0,y=0,width=416,height=244]
java.awt.Rectangle[x=416,y=0,width=16,height=244]
java.awt.Rectangle[x=432,y=0,width=15,height=244]
java.awt.Rectangle[x=447,y=0,width=16,height=244]
java.awt.Rectangle[x=463,y=0,width=15,height=244]
expected result
I would have expected to have the width of the bounds to keep the same. But it changes from 416 to 16.
The question now is
Does anybody know why this happens, or how it can be avoided??
discared WAs
A possible workaround would be to lookup the view port's view bounds. But if possible i would like to avoid the Content class making any such lookup. Another alternative would be to pass the information into the Content class, but this i would like to avoid as well.
I would have expected to have the width of the bounds to keep the same.
Why? It is so simple that it is hard to explain, but let me try.
When you scrolling, only small new portion if the JPanel is appearing if you scroll slowly.
The produced output is absolutely correct:
java.awt.Rectangle[x=0,y=0,width=416,height=244] Control is shown first time, you need to redraw it completely
java.awt.Rectangle[x=416,y=0,width=16,height=244] You scrolled to the right by 16 pixels, so only narrow strip of you control must be redrawn.
You must understand that these coordinates are related to your control which has size set to 2000x2000 pixels.
Try to scroll the window created with this code and you will see what I am talking about:
import javax.swing.*;
import java.awt.*;
import java.util.Random;
public class ScrollPaneRepaintDemo extends JPanel {
public ScrollPaneRepaintDemo() {
setPreferredSize(new Dimension(2000,2000));
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(new JScrollPane(new ScrollPaneRepaintDemo()));
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
#Override protected void paintComponent(Graphics g) {
Rectangle clip = g.getClipBounds();
g.setColor(new Color(new Random().nextInt()));
g.fillRect(clip.x, clip.y, clip.width, clip.height);
}
}
By the way - it works so because of JPanel's internal implementation. If you extend JComponent instead, the whole viewport will be clipped. I add also that JPanel repaints completely when resizing, its optimizations are only for scrolling.
public static void main(String args[]){
JFrame frame = new JFrame();
frame.setExtendedState(JFrame.MAXIMISED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
I've used this code to maximise a JFrame, but instead of actually maximising the frame, it just sets the window size to that of the screen, without actually changing the state, so clicking the maximize button doesn't actually downscale it again.
Am I using the wrong command or something?
You have an error in frame.setExtendedState(JFrame.MAXIMISED_BOTH);
You should write frame.setExtendedState(JFrame.MAXIMIZED_BOTH); instead
Have you tried this?
f.setExtendedState(f.getExtendedState() | JFrame.MAXIMIZED_BOTH);
Based on your provided example and run on Windows 7...
"Maximised" state (this is cropped version of window as the original is quite large)
"Normal" state
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ExtendedFrame {
public static void main(String[] args) {
new ExtendedFrame();
}
public ExtendedFrame() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame();
// frame.setExtendedState(JFrame.MAXIMISED_BOTH);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
You must want it maximized by default. Because the maximize button works out-of-the-box.
frame.setExtendedState(JFrame.MAXIMIZED_BOTH) works on Linux x64. Here's the program I tested with:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Test implements ActionListener {
public static void main(String... args) {
new Test();
}
private JFrame frame;
public Test() {
frame = new JFrame();
frame.add(new JLabel("Hi!"), BorderLayout.CENTER);
JButton button = new JButton("maximize");
button.addActionListener(this);
frame.add(button, BorderLayout.SOUTH);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
}
This worked for me:
We need to combine the setSize () and setExtendedState together
JFrame frame=new JFrame();
frame.setExtendedState(JFrame.MAXIMIZED_BOTH); // aligns itself with windows task bar
// set maximum screen
frame.setSize((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth(), (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight());
You should use this when applying changes
frame.setResizable(true);
Seven years late is better than never, right?
The question does not provide an SSCCE presumably because this is not all of the code involved. The tiny fragment of code provided work as it is, so practically all previous answers are saying "works for me". So, the problem certainly lies with the rest of the code, which is not shown.
We cannot be sure what the rest of the code does, but I suspect that it tries to persist the state and bounds of the frame, and to restore that state and bounds later, and that is what fails. The OP did not receive an answer 7 years ago because they did not explain what the actual problem was, but this question will be viewed by many more, so here it goes:
In theory, persisting the state and bounds of a frame should be piece of cake, but in practice it is not.
This is a very common problem in GUI applications, and it is basically due to a common mistake on behalf of the programmer. However, it should be noted that various widely used GUI frameworks (and certainly both Swing and SWT in the Java world) operate in a specific perverse way which makes it a very easy mistake to make.
The problem begins with the fact that these frameworks do not support a 'maximized' event, (duh!) so the only way you can detect that your frame has been maximized is to listen to the 'resized' event. So, you are presumably persisting the state and dimensions of your frame from within your 'resized' event handler.
The problem is further compounded by the fact that once the 'resized' event has occurred as a result of maximizing the frame, the frame bounds are the maximized bounds of your frame, which are irrelevant, and you will be shooting yourself in the foot if you make the mistake of persisting them.
So, the solution is to manually keep track of the "normal state" bounds of your frame, and only persist those. This can be accomplished as follows:
addComponentListener( new ComponentAdapter()
{
#Override public void componentResized( ComponentEvent e )
{
if( (getExtendedState() & MAXIMIZED_HORIZ) == 0 )
normalStateBounds.width = getWidth();
if( (getExtendedState() & MAXIMIZED_VERT) == 0 )
normalStateBounds.height = getHeight();
stateAndOrSizeChanged();
}
#Override public void componentMoved( ComponentEvent e )
{
if( (getExtendedState() & MAXIMIZED_HORIZ) == 0 )
normalStateBounds.x = getX();
if( (getExtendedState() & MAXIMIZED_VERT) == 0 )
normalStateBounds.y = getY();
stateAndOrSizeChanged();
}
} );
...where:
normalStateBounds is defined as private final Rectangle normalStateBounds = new Rectangle(); and contains the bounds of your component when in the "normal" (i.e. not minimized, nor maximized) state
stateAndOrSizeChanged() is your function which handles persisting the state and bounds of your frame, being careful to only persist normalStateBounds instead of the values returned by getX(), getY(), getWidth(), and getHeight().
When loading the state and bounds from persistence, you can simply invoke setBounds() followed by setExtendedState(), and you should do that before invoking setVisible( true ) to avoid the possibility of your frame appearing restored for a blink of an eye before maximizing. The call to setBounds() will set the non-maximized bounds, and the call to setExtendedState() might maximize your frame, but if you then restore it, it will assume the non-maximized bounds that you have set.
It works for me running Java 7 on a WinXP machine.
For the record, this is what an SSCCE should look like:
import javax.swing.*;
public class JFrameExtendedDemo
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 200);
f.setLocationRelativeTo(null);
f.setVisible(true);
// Then:
f.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
});
}
}
I'm using Eclipse 3.7.2 and I would like to use WindowBuilder too. My problem is it generates useless code for me. When I'm running my application I can see nothing but a little piece of the titlebar of the window of my program. This window's size is 0×0 no matter what have I set through the code. When I'm resizing it there is just a blank frame and nothing else. It turned out when I was debugging my code that the constructor - made by WindowBuilder - has been called and running without errors. However this constructor does not make any effect on my program. I have no clue what to do.
thanks
When you go "New" > "Other" > "WindowBuilder" > "Swing designer" > "JFrame" (than name your class) you should get this:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Stack extends JFrame {
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Stack frame = new Stack();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Stack() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
}
}
In oposite way: Go "Help" > "Install new software" > " already installed". Check that you have installed these things (Swing designer and below):
The best process is to let WindowBuilder create the framework of the GUI. With WB installed, just use the new Class icon in the toolbar. This will create the best method naming for WB to continue. WB cannot parse just any code. It needs to have some structure. See the example below.
I'm doing a project where i need some custom swing components. So far I have made a new button with a series of images (the Java Metal look doesn't fit with my UI at all). Ive implemented MouseListener on this new component and this is where my problem arises. My widget changes image on hover, click etc except my MouseListener picks up mouse entry into a the entire GridLayout container instead of into the image. So I have an image of about 200*100 and the surrounding container is about 400*200 and the mouseEntered method is fired when it enters that GridLayout section (even blank space parts of it) instead of over the image. How can I make it so that it is only fired when I hover over the image? Ive tried setting size and bounds and other attributes to no avail.
EDIT: Here's a demonstration of my issue. As you can see (sort of, colors are very similar) the bottom right button is highlighted just by entering its section of the GridlLayout. I only want it highlighted when I'm over the image actual, not the GridLayout section.
I Won't add the MouseListener methods because they just involve switching the displayed image.
public customWidget()
{
this.setLayout(new FlowLayout());
try {
imageDef=ImageIO.read(new File("/home/x101/Desktop/buttonDef.png"));
imageClick=ImageIO.read(new File("/home/x101/Desktop/buttonClick.png"));
imageHover=ImageIO.read(new File("/home/x101/Desktop/buttonHover.png"));
current=imageDef;
} catch (IOException e)
{
e.printStackTrace();
}
this.addMouseListener(this);
}
protected void paintComponent(Graphics g)
{
super.paintComponents(g);
g.drawImage(current, 0, 0, current.getWidth(), current.getHeight(), null);
}
EDIT: added code section
As an alternative, consider the The Button API, which includes the method setRolloverIcon() "to make the button display the specified icon when the cursor passes over it."
Addendum: For example,
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ButtonIconTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
private static void createAndShowGui() {
String base = "http://download.oracle.com/"
+ "javase/tutorial/uiswing/examples/components/"
+ "RadioButtonDemoProject/src/components/images/";
ImageIcon dog = null;
ImageIcon pig = null;
try {
dog = new ImageIcon(new URL(base + "Dog.gif"));
pig = new ImageIcon(new URL(base + "Pig.gif"));
} catch (MalformedURLException ex) {
ex.printStackTrace(System.err);
return;
}
JFrame frame = new JFrame("Rollover Test");
JPanel panel = new JPanel();
panel.add(new JLabel(dog));
panel.add(new JLabel(pig));
JButton button = new JButton(dog);
button.setRolloverIcon(pig);
panel.add(button);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
I assume your image contains ONLY 4 'customWidget' objects (in a 2x2 grid).
Your code is working as I would expect. Your MouseListener methods are responding to MouseEvents for 'customWidget' (not the image drawn in 'customWidget'), which is sized to take up 1/4 of the image, so they will respond when it enters the enlarged area. The error is actually in your Test program, because you are allowing the custom button widget to be larger than the image.
If you want a Test program that provides an image similar to yours, you should create a larger grid (say 4x4), and then only place your buttons in every other grid node. Place an empty component into the gaps.
Although I won't answer to your particular question, I hope this helps:
If the components just look wrong maybe you should reuse Swing components and just write a custom Look&Feel or theme.
It would certainly help ensuring the look of the application is consistent and at least you are using the right tool for the task you want to accomplish.
As a sidenote, be aware that Java comes with multiple Look&feels, including Look&Feels made to mimic the native OS theme.
See: http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
How would you make a JComponent (panel, frame, window, etc.) fullscreen, so that it also overlaps everything on the screen including the windows start bar?
I don't want to change the resolution or anything with the graphics device like bitdepth etc, I just want to overlap everything else.
Check out this tutorial describing Java's Full-Screen mode API.
Example code (taken from the tutorial). Note that the code operates on a Window so you would need to embed your JPanel with a Window (e.g. JFrame) in order to do this.
GraphicsDevice myDevice;
Window myWindow;
try {
myDevice.setFullScreenWindow(myWindow);
...
} finally {
myDevice.setFullScreenWindow(null);
}
You can try some of the codes in this page, allowing a container to fill the screen (so it is not a solution for an individual component, but for a set of components within a container like a JFrame)
public class MainWindow extends JFrame
{
public MainWindow()
{
super("Fullscreen");
getContentPane().setPreferredSize( Toolkit.getDefaultToolkit().getScreenSize());
pack();
setResizable(false);
show();
SwingUtilities.invokeLater(new Runnable() {
public void run()
{
Point p = new Point(0, 0);
SwingUtilities.convertPointToScreen(p, getContentPane());
Point l = getLocation();
l.x -= p.x;
l.y -= p.y;
setLocation(l);
}
});
}
...
}
You need to use the following API: http://java.sun.com/docs/books/tutorial/extra/fullscreen/index.html
Going full screen isn't as simple as making a large panel, you need to look into the underlying OS graphics. But your JPanel code should translate just fine.
I needed to search a lot, to do the same. Here is completely a working version of it by steps, so that i can find it later also, and use it.
Step 1: create a file called fullscreen.java
Step 2: copy this code and paste it as it is:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class fullscreen extends Window
{
private Button button;
public fullscreen()
{
super(new Frame());
button = new Button("Close");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});
setLayout(new FlowLayout());
add(button);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds(0,0,screenSize.width, screenSize.height);
}
public static void main(String[] args)
{
// This will take over your whole screen tested and works in my:
// Fedora 12/13/14
// CentOS 5.0
// if this works for you, in other platforms, please leave a comments which OS it worked.
// happy coding!
new fullscreen().setVisible(true);
}
}
Step 3: compile the code and run
Done.
If I were you I would try to make Java not draw the border of the Jframe, then make it take all the screen.
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import javax.swing.JFrame;
public class FenNoBorder extends JFrame {
public FenNoBorder () {
setUndecorated(true);
setVisible(true);
GraphicsEnvironment graphicsEnvironment=GraphicsEnvironment.getLocalGraphicsEnvironment();
Rectangle maximumWindowBounds=graphicsEnvironment.getMaximumWindowBounds();
setBounds(maximumWindowBounds);
}
}