Function to navigate to a web page in Java - java

I am trying to make a function that allows you to navigate to a webpage. I can how to run the function, I just don't know how to write the part of the program that accesses the webpage. Here is the code that I am using to access the function via a JButton. I would like the program to work on multiple platforms. All of the solutions I have found to this, I either don't understand well enough to modify to my needs, or it isn't multi-platform.
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton google = new JButton("Google");
linux.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
openURL("http://www.google.com/");
}
} );
JButton stackoverflow = new JButton("Stackoverflow");
JButton blah = new JButton("blah");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.add(linux);
panel.add(osx);
panel.add(windows);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
Yes I am aware the last two buttons do nothing.
Here is what I have tried so far:
public static void openURL(String url) {
String osName = System.getProperty("os.name");
try {
if (osName.startsWith("Windows"))
Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url);
else {
String[] browsers = {"firefox", "opera", "konqueror", "epiphany", "mozilla", "netscape", "chrome" };
String browser = null;
for (int count = 0; count < browsers.length && browser == null; count++)
if (Runtime.getRuntime().exec(new String[] {"which", browsers[count]}).waitFor() == 0)
browser = browsers[count];
Runtime.getRuntime().exec(new String[] {browser, url});
}
}
catch (Exception e) {
JOptionPane.showMessageDialog(null, "Error in opening browser" + ":\n" + e.getLocalizedMessage());
}
}
Unfortunately, I don't understand what this does, or how to change it to my needs.
If possible could you explain your solution so that I can understand how it works? Thanks.

You can use Desktop class which allows Java applications to interact with default applications associated with specific file types on the host platform. Here you have a tutorial on How to integrate with the Desktop class.
Remember:
Use the isDesktopSupported() method to determine whether the Desktop
API is available
I made a quick example.
import java.awt.Desktop;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class DesktopTest {
private JPanel panel;
public DesktopTest() {
panel = new JPanel();
ActionListener listener = new OpenUrLAction();
JButton googleButton = new JButton("google");
googleButton.setActionCommand("http://www.google.com");
googleButton.addActionListener(listener);
JButton stackOverButton = new JButton("stackOverflow");
stackOverButton.setActionCommand("http://www.stackoverflow.com");
stackOverButton.addActionListener(listener);
panel.add(googleButton);
panel.add(stackOverButton);
}
public JPanel getPanel() {
return panel;
}
private class OpenUrLAction implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (Desktop.isDesktopSupported()) {
try {
Desktop desktop = Desktop.getDesktop();
desktop.browse(new URI(e.getActionCommand()));
} catch (IOException | URISyntaxException e1) {
JOptionPane.showMessageDialog(null,
"An error happen " + e1.getMessage());
}
}
}
}
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("DesktopExample");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(Boolean.TRUE);
frame.add(new DesktopTest().getPanel());
// Display the window.
frame.pack();
frame.setVisible(Boolean.TRUE);
}
public static void main(String[] args) {
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
If you don't find this useful , you can find some workaround in this answer

Related

JAVA - JFrame not looking proper when called from action listener

I have a problem with one of my frames not looking as it should, when it is called upon the press of a button.
The frame looks as if it was rendered improperly, the label text in it is shortened, however when i move the same line of code outside the action listener, it works as it should.
I have a sort of main menu, with two buttons, only the Generate Menu works at the moment, it looks like this:
https://i.imgur.com/k1Ne5v9.png
The code for the action listener:
runMenuButt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Generate Menu pressed");
mF.dispose();
MenuGenerator.generateTheMenu();
}
});
The result looks wrong: https://i.imgur.com/n86y4CD.png
The frame is also unresponsive, clikcing X does not, while it should close the frame and the application.
However changing the code to:
runMenuButt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Generate Menu pressed");
//mF.dispose();
}
});
MenuGenerator.generateTheMenu();
Produces correct look: https://i.imgur.com/TFbkmAO.png
The code for the "Main menu"
public static void openMainMenu() {
Font menuFont = new Font("Courier",Font.BOLD,16);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
mF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mF.setSize(465,230);
mF.setLocation(dim.width/2-mF.getSize().width/2, dim.height/2-mF.getSize().height/2);
mF.getContentPane().setBackground(Color.WHITE);
Color blueSteel = new Color(70,107,176);
JPanel p = new JPanel();
p.setSize(600,50);
p.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
p.setLocation((mF.getWidth() - p.getWidth()) /2, 20);
p.setBackground(blueSteel);
JLabel l = new JLabel("Welcome to the menu GENERATORRRR");
l.setFont(menuFont);
l.setForeground(Color.WHITE);
p.add(l, gbc);
JButton runMenuButt = new JButton("Generate Menu");
runMenuButt.setLocation(20 , 90);
JButton manageRecipButt = new JButton("Manage Recipients");
manageRecipButt.setLocation(240 , 90);
menuUtilities.formatButton(runMenuButt);
menuUtilities.formatButton(manageRecipButt);
mF.setResizable(false);
mF.setLayout(null);
mF.add(runMenuButt);
mF.add(manageRecipButt);
mF.add(p);
mF.setVisible(true);
runMenuButt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Generate Menu pressed");
//mF.dispose();
}
});
MenuGenerator.generateTheMenu();
manageRecipButt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(null, "Not supported yet", "Function not yet available",JOptionPane.INFORMATION_MESSAGE);
}
});
//System.out.println(mF.getContentPane().getSize());
}
And the status bar:
public class StatusBar {
private static JLabel statusLabel= new JLabel("Starting");
private static JFrame statusFrame = new JFrame("Generation Status");
public static void createStatusBar() {
Font menuFont = new Font(Font.MONOSPACED,Font.BOLD,20);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
statusFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
statusFrame.setSize(700,100);
JPanel p = new JPanel();
p.setPreferredSize(new Dimension(100,100));
statusLabel.setFont(menuFont);
p.add(statusLabel);
statusFrame.add(p,BorderLayout.CENTER);
statusFrame.setLocation(dim.width/2-statusFrame.getSize().width/2, dim.height/2-statusFrame.getSize().height/2);
statusFrame.setVisible(true);
}
public static void setStatusBar(String statusText) {
statusLabel.setText(statusText);
statusLabel.paintImmediately(statusLabel.getVisibleRect());
statusLabel.revalidate();
}
public static void closeStatusBar(){
statusFrame.dispose();
}
}
I create the bar with this line:
StatusBar.createStatusBar();
Why does the status bar not render properly when the MenuGenerator.generateTheMenu(); is called from the action listener?
Here is minimal code that reproduces this behavior for anyone who would like to test it: It also uses class for the StatusBar, which is already posted.
public class MinimalClass {
private static JFrame mF = new JFrame("Main Menu");
public static void main(String[] args) {
openMainMenu();
}
public static void openMainMenu() {
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
mF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mF.setSize(465,230);
mF.setLocation(dim.width/2-mF.getSize().width/2, dim.height/2-mF.getSize().height/2);
mF.getContentPane().setBackground(Color.WHITE);
JButton runMenuButt = new JButton("Generate Menu");
runMenuButt.setLocation(20 , 90);
runMenuButt.setSize(200 , 85);
mF.setResizable(false);
mF.setLayout(null);
mF.add(runMenuButt);
mF.setVisible(true);
runMenuButt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Generate Menu pressed");
mF.dispose();
generateTheMenu();
}
});
}
public static void generateTheMenu() {
System.setProperty("sun.java2d.cmm", "sun.java2d.cmm.kcms.KcmsServiceProvider");
String rawMenuOutput = "";
try {
rawMenuOutput= getMenuInJavaNow();
} catch (Exception e){
System.out.println("Something went terribly wrong");
}
System.out.println(rawMenuOutput);
}
public static String getMenuInJavaNow() throws IOException {
String rawMenuOutput = "Restaurant Menu" ;
rawMenuOutput = rawMenuOutput + "Test line";
String []menuOtpArr = new String [3];
try {
StatusBar.createStatusBar();
TimeUnit.SECONDS.sleep(2);
StatusBar.setStatusBar("Test1");
TimeUnit.SECONDS.sleep(2);
menuOtpArr[0]="Test line";
StatusBar.setStatusBar("Test2");
TimeUnit.SECONDS.sleep(2);
menuOtpArr[1]="Test line";
StatusBar.setStatusBar("Test3");
TimeUnit.SECONDS.sleep(2);
menuOtpArr[2]="Test line";
StatusBar.setStatusBar("Test4");
TimeUnit.SECONDS.sleep(2);
StatusBar.closeStatusBar();
} catch (Exception e) {
}
for (int i=0;i < menuOtpArr.length;i++) {
rawMenuOutput = rawMenuOutput + "\n\n" +menuOtpArr[i];
}
return rawMenuOutput;
}
}
Thank you for your time
statusLabel.paintImmediately(statusLabel.getVisibleRect()); seems to masking a larger issue.
The problem is, Swing is single threaded (and NOT thread safe). This means that when you call TimeUnit.SECONDS.sleep(2); from within getMenuInJavaNow, which is called by generateTheMenu, which is called by the ActionListener, it's been called within the context of the Event Dispatching Thread.
This is putting the EDT to sleep, meaning that it isn't processing layout or paint requests (properly)
Start by having a read of Concurrency in Swing for more details
Now, you have a larger issue, how to solve it. For the answer to that question, we require a lot more context then is currently available.
The getMenuInJavaNow seems to be returning some values, to what end I'm not sure.
"A" solution, would be to use a SwingWorker (see Worker Threads and SwingWorker for more details). It provides the ability to execute long running tasks in the background, but also provides the means for sync updates back to the UI, for example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
public class MinimalClass {
private static JFrame mF = new JFrame("Main Menu");
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
openMainMenu();
}
});
}
public static void openMainMenu() {
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
mF.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mF.setLocationRelativeTo(null);
mF.getContentPane().setBackground(Color.WHITE);
JButton runMenuButt = new JButton("Generate Menu");
runMenuButt.setMargin(new Insets(25, 25, 25, 25));
JPanel buttons = new JPanel(new GridLayout(0, 2));
buttons.add(runMenuButt);
mF.add(buttons);
mF.pack();
mF.setVisible(true);
runMenuButt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Generate Menu pressed");
mF.dispose();
generateTheMenu();
}
});
}
public static void generateTheMenu() {
System.setProperty("sun.java2d.cmm", "sun.java2d.cmm.kcms.KcmsServiceProvider");
StatusBar.createStatusBar();
SwingWorker<String, String> worker = new SwingWorker<String, String>() {
#Override
protected String doInBackground() throws Exception {
String rawMenuOutput = "Restaurant Menu";
rawMenuOutput = rawMenuOutput + "Test line";
String[] menuOtpArr = new String[3];
try {
TimeUnit.SECONDS.sleep(2);
publish("1234567890123456789012345678901234567890");
TimeUnit.SECONDS.sleep(2);
publish("This is a test");
TimeUnit.SECONDS.sleep(2);
publish("More testing");
TimeUnit.SECONDS.sleep(2);
publish("Still testing");
TimeUnit.SECONDS.sleep(2);
} catch (Exception e) {
}
for (int i = 0; i < menuOtpArr.length; i++) {
rawMenuOutput = rawMenuOutput + "\n\n" + menuOtpArr[i];
}
return rawMenuOutput;
}
#Override
protected void done() {
StatusBar.closeStatusBar();
}
#Override
protected void process(List<String> chunks) {
StatusBar.setStatusBar(chunks.get(chunks.size() - 1));
}
};
worker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (worker.getState() == SwingWorker.StateValue.DONE) {
try {
String result = worker.get();
System.out.println(result);
StatusBar.closeStatusBar();
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
}
}
});
worker.execute();
}
public static class StatusBar {
private static JLabel statusLabel = new JLabel("Starting");
private static JFrame statusFrame = new JFrame("Generation Status");
public static void createStatusBar() {
Font menuFont = new Font(Font.MONOSPACED, Font.BOLD, 20);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
statusFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
statusFrame.setSize(700, 100);
JPanel p = new JPanel();
p.setBackground(Color.RED);
// p.setPreferredSize(new Dimension(100, 100));
statusLabel.setFont(menuFont);
p.add(statusLabel);
statusFrame.add(p, BorderLayout.CENTER);
statusFrame.setLocationRelativeTo(null);
statusFrame.setVisible(true);
}
public static void setStatusBar(String statusText) {
statusLabel.setText(statusText);
}
public static void closeStatusBar() {
statusFrame.dispose();
}
}
}
Observations...
static is not your friend, especially in cases like this. You really, really, really need to learn to live without it.
setLayout(null) is not doing you any favours, especially in the long run. Take the time to go through Laying Out Components Within a Container and start making proper use of layout managers, they might seem "complicated", but they will save you from a lot of hair loss
Avoid using setPreferred/Minimum/MaximumSize where ever possible, you are robing the component of the ability to provide useful rendering hints which may change across platforms and rendering pipelines
Just a quick follow up question, what is the difference between done and addPropertyListener ? Is there any? Isnt it redundant to use both?
The example here is pretty basic, for me I've used done to handle what the SwingWorker "knows" needs to be done, it doesn't however, know what is to be done with the result.
I've used the PropertyChangeListener to deal with that instead - the point - it's an example.
And I also noticed, that I dont need to actually publish, as calling StatusBar.setStatusBar(""); works as well. Is it necessary to use publish?
In a word YES. Swing is NOT thread safe, calling StatusBar.setStatusBar("") directly can lead to some weird and unexpected results. publish pushes the call into the Event Dispatching Thread, making it safe to update the UI from within.
I have the code for generating the String I want to set as the StatusBar Title in another class, not in the generateTheMenu, therefore it is more convenient for me to simply call .setStatusBar. The not minimal code I have is actually something like this
This is where things like interfaces come in really handy. You "string" generating class "could" either return the resulting text OR you could pass a reference to a interface implementation which is used to "display" it. This way, your SwingWorker could act as a consumer for the String and pass it through the publish method.
There are a number of really important concepts to understand.
You want to decouple your code. This makes it easier to change certain parts of the code without affecting the other parts
You want to be able to "code to interface, not implementation". This goes hand in hand with the first comment. Basically, you want to "hide" the implementation details as much as possible - lots of different reasons for it, but it helps keep your code lean, helps make the follow more understandable and stops one part of the code from accessing another it really has no responsibility to do so (is the string generation really responsible for updating the status bar? IMHO - not really)
There is also a swagger of design patterns available to make solving issues easier. I've already mentioned the concept of "produce/consumer", but this is just one
The "Event Dispatching Thread"
The Event Dispatch Thread
Java Event-Dispatching Thread explanation
Swing threading and the event-dispatch thread

Java Modal dialog freezes whole application when whole application loses focus right before it is opened

Once the steps below are taken, the whole application is frozen and the modal dialog cannot be closed.
(This is related to another question but this time we have a reproducible scenario)
The steps:
Open dropdown
Select "Han-Ra" (the last value in the drop down)
After this, trying to resize or close the modal dialog will not succeed. It reproduces 1 out of 3 times (might be easier to reproduce if you do the selection by arrow down but happens with mouse selection also)
This happens on jdk 1.8 (tried 1.8.0_162 and 1.8.0_144) and jdk 10 (10.0.1) but not when using 1.7 (tried 1.7.0_80)
This is just the most obvious case we could find but it randomly (rarely) happens for most modal dialogs.
Anyone else had this problem and found a workaround? We'll report it to Oracle but we'd be more interested in a workaround.
import javax.swing.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
public class FreezePleeze {
public static final Object[] ALL_THE_SINGLE_LADIES = {"Rahan", "Crao", "Naouna", "Han-ra"};
public static void main(String[] args) {
new FreezePleeze();
}
public FreezePleeze() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JButton push_me = new JButton("Push me");
JFrame frame = new JFrame("Mmmmm");
JPanel containerPanel = new JPanel();
frame.add(containerPanel);
final JComboBox<Object> comboBox = new JComboBox<>(ALL_THE_SINGLE_LADIES);
containerPanel.add(comboBox);
frame.setSize(300, 300);
comboBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JDialog jDialog = new JDialog((JFrame) null, true);
jDialog.add(push_me);
if (comboBox.getSelectedIndex() == ALL_THE_SINGLE_LADIES.length - 1) {
jDialog.setLocationRelativeTo(frame);
jDialog.setSize(300, 300);
jDialog.setVisible(true);
}
}
});
comboBox.addPopupMenuListener(new PopupMenuListener() {
#Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
}
#Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
try {
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_WINDOWS);
robot.keyRelease(KeyEvent.VK_WINDOWS);
} catch (AWTException e1) {
e1.printStackTrace();
}
push_me.setText("Finished counting");
}
#Override
public void popupMenuCanceled(PopupMenuEvent e) {
}
});
frame.setVisible(true);
}
});
}
}
I can reproduce your problem. The solution is to submit the correct window to the constructor of your dialog:
Example:
JDialog jDialog = new JDialog(frame, true);
or, if you have no window instance when you create a dialog:
JDialog jDialog = new JDialog(FocusManager.getCurrentKeyboardFocusManager().getActiveWindow(),
ModalityType.APPLICATION_MODAL);

Creating a Countdown Timer inside of a JFrame

I have been struggling on this problem for a while so I thought I'd seek out some help.
I am creating an application for a game which requires me to make a dynamic countdown timer. By dynamic I mean being able to put your desired countdown timer in as the consumer. The problem I'm having is making my code wait 1000 milliseconds to execute the update code with the correct time. I am attempting to use the sleep functionality to do this...
This is not the application I am making this is just to simplify my problem down as much as I could for anyone willing to help me. Everything in here is directly from WindowBuilder in Eclipse IDE. The issue I'm having is getting the Thread thread = new Thread(); work with Thread.sleep(1000); for the full 1 second delay.
package test;
import java.awt.EventQueue;
import javax.swing.JFrame;
import java.awt.Color;
import javax.swing.JLabel;
import java.awt.BorderLayout;
import javax.swing.SwingConstants;
import java.awt.Font;
public class test {
private JFrame frame;
/**
*
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
test window = new test();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public test() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.getContentPane().setBackground(Color.RED);
JLabel lblNewLabel = new JLabel("Test");
lblNewLabel.setFont(new Font("Tahoma", Font.PLAIN, 62));
lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
frame.getContentPane().add(lblNewLabel, BorderLayout.CENTER);
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Thread thread = new Thread();
for(int i = 60;i>=0;i--){
thread.sleep(500);
lblNewLabel.setText("Test" + i);
}
}
}
If you throw this code in your IDE an error that reads Unhandled exception InterruptedException comes up. If I add in throws declarations the code just messes all up truthfully I don't know what the problem is there.
How can I fix or work around this?
Here's another way to do it. Please note this code is not test.
private void initialize() {
...
new Thread() {
int counter = 10;
public void run() {
while(counter >= 0) {
lblNewLabel.setText("Test" + (counter--));
try{
Thread.sleep(1000);
} catch(Exception e) {}
}
}
}.start();
}

Detect CTRL+V in Swing App but keep original function

Wrting a chat application, I want the user to be able to send images out of his/her clipboard. For this, I would like to catch any CTRL+Vkeyboard input. Since pasting text should be possible as by default, the original ctrl+v-function (pasting text) must not be overridden.
I see can two approaches, of which none works for me:
1st: Taken from the official Java documentation: KEY LISTENER
editorPane.addKeyListener(new KeyListener() {
#Override
public void keyPressed(KeyEvent e) {
e.getKeyChar()
// when I press ctrl+v, ^ this is falsely a white square character, looks like (U+25A1). Plain v without ctrl does work.
e.getKeyCode()
// ^ this is falsely 0
// (e.getModifiersEx() correctly returns InputEvent.CTRL_DOWN_MASK)
}
2nd: KEY BINDING
InputMap iMap = editorPane.getInputMap(condition);
ActionMap aMap = editorPane.getActionMap();
iMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK), "ctrlV");
aMap.put("ctrlV", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
// works, but overrides natural ctrl+v function!
}
});
Any ideas?
Note: I am using a "foreign" keyboard layout (German). But I can't see why this should make any difference - I would pretty much like to have my application work internationally.
Cheers
edit. Alt+SomeKey however is correctly recognized by the KeyListener
edit2. after changing keyboard layout to US, problem persists.
Stick to Keybindings: KeyListener is a low-level API, while Keybindings will provide you consistent, predictable and robust behaviour.
The solution here is quite easy. You can simply combine the actions yourself by adding a CombinedAction class that will execute the "original" action bound to CTRL+V and the "custom" action you want to execute.
See a small example below combining both actions (here my custom action is a Sysout):
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JComponent;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
public class TestEditorPane {
private JEditorPane editorPane;
public static class CombinedAction implements ActionListener {
private final ActionListener action1;
private final ActionListener action2;
public CombinedAction(ActionListener action1, ActionListener action2) {
super();
this.action1 = action1;
this.action2 = action2;
}
#Override
public void actionPerformed(ActionEvent e) {
if (action1 != null) {
action1.actionPerformed(e);
}
if (action2 != null) {
action2.actionPerformed(e);
}
}
}
public TestEditorPane() {
}
private void initUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// JTEXTBOX
editorPane = new JEditorPane();
KeyStroke ctrlV = KeyStroke.getKeyStroke(KeyEvent.VK_V, KeyEvent.CTRL_DOWN_MASK);
final ActionListener ctrlVAction = editorPane.getActionForKeyStroke(ctrlV);
editorPane.registerKeyboardAction(new CombinedAction(ctrlVAction, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("This is my action on CTRL+V");
}
}), ctrlV, JComponent.WHEN_FOCUSED);
// JSCROLLPANE
JScrollPane scroll1 = new JScrollPane(editorPane);
scroll1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scroll1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
frame.add(scroll1);
frame.setSize(400, 400);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
TestEditorPane test = new TestEditorPane();
test.initUI();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}

JDesktopPane resize

We have a application with two JFrames with two JDesktopPanes.
We need to move an internal frame from one frame to another.
The problem we have is that after we move the internalframe from first window to the second window, when we resize the fist window, the internal frame of the second window also gets resized.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyVetoException;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
class FirstFrame extends JFrame
{
JDesktopPane desktopPane = new JDesktopPane();
SecondFrame secondFrame;
public FirstFrame(SecondFrame secondFrame)
{
this.secondFrame = secondFrame;
setTitle("FirstFrame example");
setDefaultCloseOperation(EXIT_ON_CLOSE);
add(desktopPane);
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("File");
JMenuItem item = new JMenuItem("Move");
item.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent actionevent)
{
moveFrame();
}
});
menu.add(item);
menuBar.add(menu);
setJMenuBar(menuBar);
}
public void addAnInternalFrame()
{
JInternalFrame frame = new JInternalFrame();
frame.setTitle("An Internal Frame");
desktopPane.add(frame);
frame.setVisible(true);
frame.setMaximizable(true);
try
{
frame.setSelected(true);
frame.setMaximum(true);
}
catch (PropertyVetoException e)
{
e.printStackTrace();
}
}
public void moveFrame()
{
JInternalFrame selectedFrame = desktopPane.getSelectedFrame();
desktopPane.remove(selectedFrame);
desktopPane.repaint();
secondFrame.addInternalFrame(selectedFrame);
}
}
class SecondFrame extends JFrame
{
JDesktopPane desktopPane = new JDesktopPane();
public SecondFrame()
{
setTitle("SecondFrame example");
setDefaultCloseOperation(EXIT_ON_CLOSE);
add(desktopPane);
}
public void addInternalFrame(JInternalFrame frame)
{
desktopPane.add(frame);
}
}
public class DesktopPaneExample
{
public static void main(String args[]) throws PropertyVetoException
{
SecondFrame secondFrame = new SecondFrame();
FirstFrame firstFrame = new FirstFrame(secondFrame);
firstFrame.setSize(400, 400);
firstFrame.setLocation(100, 100);
firstFrame.setVisible(true);
firstFrame.addAnInternalFrame();
secondFrame.setSize(400, 400);
secondFrame.setLocation(520, 100);
secondFrame.setVisible(true);
}
}
In the above sample application, to reproduce
1) click menu File>move
2) resize the first window
NOTE: This is reproducable in Java 1.7 only. I use jdk1.7.0_03.
Update: add more information
This was not reproducible on Java 1.6 (jdk1.6.0_21)
The issue is due to Java 7's tweaking on javax.swing.plaf.basic.BasicInternalFrameUI implementation.
Java 1.6 Code
public void propertyChange(PropertyChangeEvent evt) {
if ((frame.getParent() != null) && !componentListenerAdded) {
f.getParent().addComponentListener(componentListener);
componentListenerAdded = true;
} else if ((newValue == null) && componentListenerAdded) {
if (f.getParent() != null) {
f.getParent()
.removeComponentListener(componentListener);
}
componentListenerAdded = false;
}
Java 1.7 Code
public void propertyChange(PropertyChangeEvent evt) {
if ((frame.getParent() != null) && !componentListenerAdded) {
f.getParent().addComponentListener(componentListener);
componentListenerAdded = true;
}
NOTE: The else if condition was removed. This is the culprit.
I suggest you 2 options:
Option one
JInternalFrame selectedFrame = desktopPane.getSelectedFrame();
desktopPane.remove(selectedFrame);
desktopPane.repaint();
secondFrame.updateUI(); // The magic part, less expensive execution.
secondFrame.addInternalFrame(selectedFrame);
Option two
You may need to recompile javax.swing.plaf.basic.BasicInternalFrameUI.java with above "else if" condition and add to your rt.jar library's javax.swing.plaf.basic location.
I have attached the recompiled files for Java 1.7.0_25 at http://www.datafilehost.com/d/dfb7238c
Hope this helps!!!
Regards,
Nilindra
It seems as if adding the frame while in it's maximum state is the culprit. To maintain it's current size on the 1st frame over to the 2nd frame, try this:
public void moveFrame()
{
JInternalFrame selectedFrame = desktopPane.getSelectedFrame();
Dimension currentSize = selectedFrame.getSize();
try
{
selectedFrame.setMaximum(false);
}
catch (PropertyVetoException ex)
{
ex.printStackTrace();
}
selectedFrame.setSize(currentSize);
desktopPane.remove(selectedFrame);
desktopPane.repaint();
secondFrame.addInternalFrame(selectedFrame);
}
EDIT:
After reading the API for Container#remove(Component c), I got this idea that seems to work:
public void moveFrame()
{
final JInternalFrame selectedFrame = desktopPane.getSelectedFrame();
desktopPane.remove(selectedFrame);
desktopPane.repaint();
SwingUtilities.updateComponentTreeUI(selectedFrame);
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
secondFrame.addInternalFrame(selectedFrame);
}
});
}

Categories