Setting a JFrame without overlapping with taskbar - java

I need to have a undecorated JFrame(setUndecorated(true)) which need to be shown fullscreen, without overlapping with the taskbar.
I have tried the below solutions.
Calling setExtendedState(MAXIMIZED_BOTH).
Advantage:
This works fine as expected, i.e., the window is getting adjusted itself dynamically, except it has the below issues.
Issues
Initially the window occupies the fullscreen
Though the frame get adjusted itself dynamically, it overlaps with the taskbar.
Tried the below solution as stated in Does JFrame.setExtendedState(MAXIMIZED_BOTH) work with undecorated frames?
GraphicsConfiguration config = aFrame.getGraphicsConfiguration();
Rectangle usableBounds = SunGraphicsEnvironment.getUsableBounds(config.getDevice());
aFrame.setBounds(0, 0, usableBounds.width, usableBounds.height);
Advantage:
I am not getting overlaps and window looks fine.
Issue:
Window is not adjusting itself dynamically when the taskbar position/size is changed.
Any help would be greatly appreciated.
I thought of a design. But not sure about its feasibility. I can use the setBounds(). But then I need my frame to be notified when the task bar is adjusted or repositioned. Is there a way?

Able to able to fix the above issue with the below code,
Rectangle usableBounds = SunGraphicsEnvironment.getUsableBounds(config.getDevice());
setMaximizedBounds(usableBounds);
setExtendedState(MAXIMIZED_BOTH);
So by getUsableBounds I am able to get the bounds leaving the taskbar. And hence I am using setExtendedState(MAXIMIZED_BOTH) the window is getting updated automatically when I re-size/re-position the taskbar. :-)

final Point x = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
Have a separate thread to check whether taskbar get changed. If so update size
new Thread(new Runnable() {
#Override
public void run() {
if (x.equals(GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint())) {
Rectangle r = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
setSize(r.getSize());
}
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
Logger.getLogger(NewJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
}
}).start();

Related

SWT: Change style of a Shell at runtime

Is there a way to change the style of a Shell at runtime?
I would like to have a shell not resizable but capable to fill, with its content, the whole screen, when it's in fullscreen. Is there a way to accomplish that?
In other words, when a Shell is not resizable and it has for example a Background Image I get this in full screen :
On the other hand when the Shell is resizable and I go in full screen I get this:
So would like to obtain the second effect but with a not resizable Shell.
Any help would be appreciated.
Following Stefan's comment, I was able to do it listening to the resize event and checking the fullscreen flag, resizing appropriately the shell's size to the monitor size when it's in full screen and to normal size when is not. Here the code that does the trick:
shell.addListener(SWT.Resize, new Listener() {
#Override
public void handleEvent(Event arg0) {
if (shell.getFullScreen()) {
Rectangle r = getMonitorSize(shell);
shell.setSize(r.width, r.height);
shell.redraw();
} else {
shell.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
shell.redraw();
}
}
});

Internalframe size is not always maximized ( alternating)

I am facing a weird issue that I can't see to understand why. I have a frame with an Internal JFrame that opens upon a menu click. This internal frame is supposed to be always maximized. When I run the program and click on the menu then it does what is expected. If I close the internal jframe and click the button again, the internal jframe is minimized. If I close it and click the button then it is maximimzed!! Why is it alternating like that. Here is the code that open the internal jframe. This method is inside the JFrame class
private void onButtonClick(){
InternalFrameProp intFrame = new InternalFrameProp ();
intFrame.setVisible(true);
jDesktopPane1.add(intFrame );
try {
intFrame .setMaximum(true);
} catch (PropertyVetoException ex) {
Logger.getLogger(MainHomePage.class.getName()).log(Level.SEVERE, null, ex);
}
}
As I was trying to put a runnable example, I noticed that this behaviour only happen in the Windows look and feel. To get around I did
jDesktopPane1.setDesktopManager(new DefaultDesktopManager());
That seemed to fix the problem! I have no idea why but it worked!

JavaFx/ Swing window does not open after update to Java 1.8u40

We have an javafx application developed mainly in java 1.7 and tested in 1.8. It was running fine until java 1.8u35. Now we discovered, JavaFx windows are not going to open in 1.8u40 after upgrade. Even worse, the modal windows are blocking the entire tab/ browser of being used. So the user is just able to close the browser using the task manager.
We use javafx.embed.swing.JFXPanel to embed jfx-code into swing legacy code.
I have completely no clue what might be the problem, as there are no errors displayed in client's java console.
UPDATE:
I reviewed the known issues list for java1.8 here. The only thing I would probably link to our issue is this bug:
BUG-RT-32597: The SwingNode class does not support High DPI displays.
So I tried lowering the screen resolution (1280x1024 to 800x600) but without success.
Does anyone faced a similar issue before and knows what might help?
UPDATE:
I tried to better track down the problem but with not much luck.
To make it more visible, this is basically whats going on on window loading:
public static void initWindow(JDialog dialog){
final JFXPanel jfx = new JFXPanel();
Platform.runLater(new Runnable() {
public void run() {
System.out.println("JFXPanel");
}
});
Runnable r = new Runnable() {
public void run() {
AnchorPane root = new AnchorPane;
//... do some content loading
Scene scene = new Scene(root,width,height);
System.out.println("test");
}
};
dialog.add(jfx);
System.out.println("added jfx panel.");
dialog.pack();
System.out.println("packed jfx panel.");
dialog.setLocationRelativeTo(null);
System.out.println("loaded.");
}
I thought execution is going to stop somewhere, but its running through the entire function as usual. Nevertheless the window is not showing up.
UPDATE:
Not completely correct, my last comment, as I found out:
Around the above function, the following happens:
initWindow(this); //this is extending java.swing.JDialog
System.out.println("this comment is printed to console");
super.setVisible(true); //this is not executed properly. if removed, browser will not be blocked, but window doesnt show up either
System.out.println("this comment is not printed to console";
So, in general, there is the JDialog which gets packed with a JfxPanel. When calling setVisible() method from the JDialog class, the Application gets blocked but the window doesnt show up. Actually, in the thumbnail screen (alt+tab) it is shown as a container inside the application.
When removing the setVisible call, the browser does not get blocked, but also the window does not show up. Unfortunately, I did not find the JDialog class code to look up, what's going on inside setVisible().
Any ideas, what might be wrong with our setup or the setVisible method?
We had a similar problem. While comparing the Java sources of 1.8.0_31 and 1.8.0_45 we found out that there were some changes in the JFXPanel source code introduced with 1.8.0_45 that may cause problems in the following situation:
initialize modal JDialog with JFXPanel (executed on Swing's EDT)
initialize and set FX scene on JFXPanel in FX task (executed on FX Thread)
wait for FX task to be finished (wait on EDT)
pack() and show() JDialog (continued on EDT, blocks program execution)
continue with program execution after user closed JDialog (on EDT)
We use this workflow in order to wait for some user input being shown in a new modal JDialog and continue normal programm execution on EDT afterwards.
In 1.8.0_31, the preferred size of JFXPanel seems to be set in FX thread which allows JDialog.pack() to determine the correct bounds.
In 1.8.0_45, the preferred size of JFXPanel seems to be set not in FX thread anymore but in EDT after all pending AWT events are executed. So, when (4) is executed, JDialog.pack() does not know about the preferred size of the scene. As a consequence, the dialog has no content, or does not show up if undecorated as described in the original question above.
Here is a complete example to reproduce the different behaviour:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// create JDialog on EDT
final JDialog dialog = new JDialog((JDialog)null, "JDialog");
// initialize FX platform and create JFXPanel
final JFXPanel jfxPanel = new JFXPanel();
// add resize listener for JFXPanel
jfxPanel.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
// not called in 1.8.0_45
System.out.println("JFXPanel.getSize(): "+jfxPanel.getSize());
}
});
// set FX Scene on JFXPanel and wait until finished
runAndWait(new Runnable() {
public void run() {
Text text = TextBuilder.create().text("JavaFx content").y(20).build();
Group root = new Group(text);
Scene scene = new Scene(root);
jfxPanel.setScene(scene);
}
});
// show undecorated modal JDialog with FX content
System.out.println("JFXPanel.getPreferredSize(): "+jfxPanel.getPreferredSize());
dialog.setUndecorated(true);
dialog.add(jfxPanel);
dialog.pack();
dialog.setModal(true);
System.out.println("JDialog.setVisible()");
dialog.setVisible(true);
}
});
}
private static void runAndWait(Runnable r) {
try {
FutureTask<Object> task = new FutureTask<Object>(r, null);
Platform.runLater(task);
task.get();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
When running this program, componentResized() is called only in 1.8.0_31 but not in 1.8.0_45.
A possible fix while keeping the synchronous program workflow on EDT is to replace JDialog.pack() with JDialog.setSize(...), e. g. by setting a constant size or by using the size of the FX scene that could be determined using root.getBoundsInLocal().
I encountered the same behaviour described by #Peter using 1.8.0_121.
I was able to get dialog.pack() to work using a window listener.
dialog.addWindowListener( new WindowAdapter() {
#Override
public void windowOpened(WindowEvent e) {
((JDialog)e.getSource()).pack();
}
});

java: TrayIcon right click disabled on Mac OsX

I'm trying to develop a Mac OsX app provided by a system tray icon, so after the first attempt with the simplest code to achieve it I noticed that every apps tray icon's (both system and user apps) on mac osX (10.8) allows to activate the relative popup menu with both left and right click on it but with my project only the left (MouseEvent.BOTTON1) button causes the popup menu to pulldown. Here's my code:
public class SystemTrayDemo
{
private SystemTray tray;
private TrayIcon tray_icon;
public SystemTrayDemo()
{
if (!SystemTray.isSupported())
{
JOptionPane.showMessageDialog(null, "System tray not supported!");
return;
}
else
tray = SystemTray.getSystemTray();
final PopupMenu popup = new PopupMenu();
MenuItem exit = new MenuItem("Exit");
exit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if (tray != null)
{
tray.remove(tray_icon);
System.exit(0);
}
}
});
popup.add(exit);
//add tray icon
tray_icon = new TrayIcon(getIcon("images/wifi.png"), "Open documents...", popup);
tray_icon.setImageAutoSize(true);
try
{
tray.add(tray_icon); // adds icon
}
catch (AWTException ex) {}
}
private Image getIcon(String name)
{
URL _url = getClass().getResource(name);
return new ImageIcon(_url).getImage();
}
public static void main(String args[])
{
new SystemTrayDemo();
}
}
but how I already said, only through left mouse button click.
So during a further attempt I've tried to mimic the behavior of the tray icons of every other apps using a MouseListener and firing a left button event on right click event using dispatchEvent() method like so:
public static void fireMouseEvent(Component c)
{
MouseEvent me = new MouseEvent(c, // which
MouseEvent.MOUSE_CLICKED, // what
System.currentTimeMillis(), // when
MouseEvent.BUTTON1_MASK, // no modifiers
0, 0, // where: at (10, 10}
1, // only 1 click
true); // popup trigger
c.dispatchEvent(me);
}
the event will handled by the mouse listener but obviously TrayIcon Class is not a Component subclass and therefore the source of MouseEvent is null and I get a NPE. Here's my MouseListener:
class MouseAdapt extends java.awt.event.MouseAdapter
{
public void mouseClicked(java.awt.event.MouseEvent me)
{
int button = me.getButton();
if(button == java.awt.event.MouseEvent.BUTTON3)
{
fireMouseEvent(me.getComponent());
}
}
}
try
{
tray.add(tray_icon); // aggiungi l'icona
tray_icon.addMouseListener(new MouseAdapt());
}
catch (AWTException ex) {}
Sorry for my english, I hope that someone who have ever had some experience with that kind of projects can help me. I've searched for hours but with no luck. Thank You for your help.
Edit: There's now a library working to fix all of this here: https://github.com/dorkbox/SystemTray
to activate the [TrayIcon] relative popup menu with both left and right click
This is simply not possible on Mac + Java currently. Using reflection to invoke the underlying triggers doesn't seem to help. This is a bug.
https://bugs.openjdk.java.net/browse/JDK-8041890
only the left (MouseEvent.BOTTON1) button causes the popup menu to pulldown. Here's my code
Even this is broken in some Java versions (7u79), fixed with an upgrade...
https://bugs.openjdk.java.net/browse/JDK-7158615
Cross-Platform TrayIcon Support:
Albeit slightly off-topic, I wanted to add, some projects use a JXTrayIcon to accomplish some fancy drop-down menus in Linux/Windows, etc. These also cause problems on Mac despite a click-bug it already suffers from today as well as bugs with Gnome3 requiring a completely separate hack. But on Mac, any attempt to use the decorated menus causes the menu to linger and is a very bad experience for the end-user. The solution I settled on was to use AWT for Mac, Swing for everything else. The Java TrayIcon support is in dire need of a rewrite. JavaFX claims to help this initiative, but it's staged for Java 9. In the mean time, I'm sticking to OS-dependent hacks.
Related Tray Issues for Other Platforms
Furthermore, some Linux distributions like Ubuntu have removed the tray icon by default in the Unity desktop, causing further headaches. https://askubuntu.com/a/457212/412004
In addition, the transparency of the icon is replaced with a gray color on Gtk/Gnome or Qt/KDE powered desktops (Both OpenJDK and Oracle JRE suffer this)
https://stackoverflow.com/a/3882028/3196753
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6453521
In addition, Gnome3 powered desktops may show it in the wrong corner, not at all, or it may show but be unclickable (Both OpenJDK and Oracle JRE suffer this)
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=660157
https://bugzilla.redhat.com/show_bug.cgi?id=1014448
In addition to that, high-DPI screens on Windows have a bug that draws the icon incorrectly: Windows 8 Distorts my TrayIcon
So in summary, the state of the System Tray in Java is OK, but due to the combination of factors is quite fragmented and buggy in JDK6, JDK7 and JDK8.

Trying to bring swing frame to front before taking a screenshot but getting artifacts

I have a part of my app that takes a screenshot of a certain window but before I do so I want to bring the window to the front. This works fine on my Mac machine but when I tested it on in Windows XP on parallels the screenshot always has a grayed out area where the overlapping window was. It seems the screenshot is always taken while the window I want on top is being transferred to the top. I've tried using both:
frame.setVisible(true);
and
frame.setAlwaysOnTop(true);
Does anyone have a reasonable solution for this issue?
If you are trying to take a screenshot of a window w painted by Java, you can just ask it to paint itself on a
BufferedImage bi = new BufferedImage(
w.width, w.height, BufferedImage.TYPE_INT_RGB);
Graphics g = bi.getGraphics();
by calling the windows' paint(g) method. You can then save the BufferedImage to a file. If you are grabbing an external window, then I believe Oscar Reyes has given you all the answers.
You could add a delay the the thread that takes the screenshot.
You could fire the screenshot from the frame when the it has gained focus:
class ScreenshotShooter implements FocusListener {
public void focusGained( FocusEvent e ) {
// smile.....
// you may add a sec of delay here just be be sure.
}
public void focusLost( FocusEvent e ) {}
}
FocusListener focusListener = new ScreenshotShooter();
frame.addFocusListener( focusListener );
frame.setVisible( true ); // should autofire
frame.remoe( focusListener);
You can do both.

Categories

Resources