I have a Java program which until now used to get the input from command line and then proceed accordingly.
Now, I want to have a basic GUI for this. It will need a few buttons which will trigger the events. I am experienced in HTML and JavaScript. Is it possible to write in HTML (or similar syntax) to generate the GUI?
I don't want to go in Swing and awt solution, because I would rather concentrate on the main program than on the GUI.
Here's another alternative. See also How to Use HTML in Swing Components.
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.io.File;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
/**
* #see http://stackoverflow.com/a/10067256/230513
* #see http://stackoverflow.com/a/7454691/230513
*/
public class Pathfinder extends JPanel {
private static final int TEXT_SIZE = 32;
private JTextField srcField = new JTextField(TEXT_SIZE);
private JTextField dstField = new JTextField(TEXT_SIZE);
private JTextField valueField1 = new JTextField(TEXT_SIZE);
private JTextField valueField2 = new JTextField(TEXT_SIZE);
private String srcPath, dstPath, value1, value2;
public Pathfinder() {
super(new GridLayout(0, 1));
this.add(createPathPanel("Source Directory", srcField));
this.add(createPathPanel("Target Directory", dstField));
this.add(createFieldPanel("Some Value:", valueField1));
this.add(createFieldPanel("Another Value:", valueField2));
JPanel submitPanel = new JPanel();
submitPanel.add(new JButton(new AbstractAction("Submit") {
#Override
public void actionPerformed(ActionEvent e) {
srcPath = srcField.getText();
dstPath = dstField.getText();
value1 = valueField1.getText();
value2 = valueField2.getText();
process();
}
}));
this.add(submitPanel);
}
private void process() {
// see ProcessBuilder http://stackoverflow.com/questions/5740390
System.out.println(srcPath);
System.out.println(dstPath);
System.out.println(value1);
System.out.println(value2);
}
private JPanel createPathPanel(String name, final JTextField jtf) {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
panel.add(new JButton(new AbstractAction(name) {
#Override
public void actionPerformed(ActionEvent e) {
JFileChooser jfc = new JFileChooser(
new File(System.getProperty("user.dir")));
jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int result = jfc.showOpenDialog(Pathfinder.this);
if (result == JFileChooser.APPROVE_OPTION) {
jtf.setText(jfc.getSelectedFile().getPath());
}
}
}));
panel.add(jtf);
return panel;
}
private JPanel createFieldPanel(String name, JTextField jtf) {
JPanel panel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
panel.add(new JLabel(name));
panel.add(jtf);
return panel;
}
private void display() {
JFrame f = new JFrame("Pathfinder");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Pathfinder pf = new Pathfinder();
if (args.length > 0) {
pf.srcPath = args[0];
pf.dstPath = args[1];
pf.process();
} else {
pf.display();
}
}
});
}
}
I want to have a basic GUI for this. It will need a few buttons which will trigger the events.
This 'basic GUI' goes slightly beyond the spec. to add an output area.
import java.awt.*;
import javax.swing.*;
class SimpleEventGUI {
SimpleEventGUI() {
JPanel gui = new JPanel(new BorderLayout());
JToolBar toolBar = new JToolBar();
for (int ii=1; ii<6; ii++) {
toolBar.add(new JButton("Event " + ii));
if (ii%2==0) {
toolBar.addSeparator();
}
}
gui.add(toolBar, BorderLayout.NORTH);
gui.add( new JScrollPane(new JTextArea(5,30)), BorderLayout.CENTER );
JOptionPane.showMessageDialog(null, gui);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new SimpleEventGUI();
}
});
}
}
You may consider Google Web Toolkit with Window Builder which allow you to build a rich internet interface using Java and interact with the existing logic.
If you want something quick, you can build a Swing GUI using Window Builder
Related
a basic problem that i can't figure out, tried a lot of things and can't get it to work, i need to be able to get the value/text of the variable
String input;
so that i can use it again in a different class in order to do an if statement based upon the result
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
public class pInterface extends JFrame {
String input;
private JTextField item1;
public pInterface() {
super("PAnnalyser");
setLayout(new FlowLayout());
item1 = new JTextField("enter text here", 10);
add(item1);
myhandler handler = new myhandler();
item1.addActionListener(handler);
System.out.println();
}
public class myhandler implements ActionListener {
// class that is going to handle the events
public void actionPerformed(ActionEvent event) {
// set the variable equal to empty
if (event.getSource() == item1)// find value in box number 1
input = String.format("%s", event.getActionCommand());
}
public String userValue(String input) {
return input;
}
}
}
You could display the window as a modal JDialog, not a JFrame and place the obtained String into a private field that can be accessed via a getter method. Then the calling code can easily obtain the String and use it. Note that there's no need for a separate String field, which you've called "input", since we can easily and simply extract a String directly from the JTextField (in our "getter" method).
For example:
import java.awt.Dialog.ModalityType;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import javax.swing.*;
import javax.swing.text.JTextComponent;
public class TestPInterface {
#SuppressWarnings("serial")
private static void createAndShowGui() {
final JFrame frame = new JFrame("TestPInterface");
// JDialog to hold our JPanel
final JDialog pInterestDialog = new JDialog(frame, "PInterest",
ModalityType.APPLICATION_MODAL);
final MyPInterface myPInterface = new MyPInterface();
// add JPanel to dialog
pInterestDialog.add(myPInterface);
pInterestDialog.pack();
pInterestDialog.setLocationByPlatform(true);
final JTextField textField = new JTextField(10);
textField.setEditable(false);
textField.setFocusable(false);
JPanel mainPanel = new JPanel();
mainPanel.add(textField);
mainPanel.add(new JButton(new AbstractAction("Get Input") {
#Override
public void actionPerformed(ActionEvent e) {
// show dialog
pInterestDialog.setVisible(true);
// dialog has returned, and so now extract Text
textField.setText(myPInterface.getText());
}
}));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
// by making the class a JPanel, you can put it anywhere you want
// in a JFrame, a JDialog, a JOptionPane, another JPanel
#SuppressWarnings("serial")
class MyPInterface extends JPanel {
// no need for a String field since we can
// get our Strings directly from the JTextField
private JTextField textField = new JTextField(10);
public MyPInterface() {
textField.addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent e) {
JTextComponent textComp = (JTextComponent) e.getSource();
textComp.selectAll();
}
});
add(new JLabel("Enter Text Here:"));
add(textField);
textField.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Window win = (Window) SwingUtilities.getWindowAncestor(MyPInterface.this);
win.dispose();
}
});
}
public String getText() {
return textField.getText();
}
}
A Good way of doing this is use Callback mechanism.
I have already posted an answer in the same context.
Please find it here JFrame in separate class, what about the ActionListener?.
Your method is a bit confusing:
public String userValue(String input) {
return input;
}
I guess you want to do something like this:
public String getInput() {
return input;
}
public void setInput(String input) {
this.input = input;
}
Also your JFrame is not visible yet. Set the visibility like this setVisible(true)
So I've built a very basic Web browser - I'm trying desperately to remove the contents of the address bar when a user clicks on it (JTextField) this appears with some text in as default. Any advice is appreciated.
Have a great day!
MY CODE
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class Web_Browser extends JFrame {
private final JTextField addressBar;
private final JEditorPane display;
// Constructor
public Web_Browser() {
super("Web Browser");
addressBar = new JTextField("Click & Type Web Address e.g. http://www.google.com");
addressBar.addActionListener(
new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
loadGo(event.getActionCommand());
}
}
);
add(addressBar, BorderLayout.NORTH);
display = new JEditorPane();
display.setEditable(false);
display.addHyperlinkListener(
new HyperlinkListener(){
#Override
public void hyperlinkUpdate(HyperlinkEvent event){
if(event.getEventType()==HyperlinkEvent.EventType.ACTIVATED){
loadGo(event.getURL().toString());
}
}
}
);
add(new JScrollPane(display), BorderLayout.CENTER);
setSize(500,300);
setVisible(true);
}
// loadGo to sisplay on the screen
private void loadGo(String userText) {
try{
display.setPage(userText);
addressBar.setText(userText);
}catch(IOException e){
System.out.println("Invalid URL, try again");
}
}
}
Use a FocusListener. On focusGained, select all.
addressBar.addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent e) {
JTextComponent textComponent = (JTextComponent) e.getSource();
textComponent.selectAll();
}
});
For example:
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import javax.swing.*;
import javax.swing.text.JTextComponent;
#SuppressWarnings("serial")
public class FocusExample extends JPanel {
private static final int TF_COUNT = 5;
private JTextField[] textFields = new JTextField[TF_COUNT];
public FocusExample() {
for (int i = 0; i < textFields.length; i++) {
textFields[i] = new JTextField("Foo " + (i + 1), 10);
textFields[i].addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent e) {
JTextComponent textComponent = (JTextComponent) e.getSource();
textComponent.selectAll();
}
});
add(textFields[i]);
}
}
private static void createAndShowGui() {
FocusExample mainPanel = new FocusExample();
JFrame frame = new JFrame("FocusExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
This gives the user the option of leaving the previous text in place, of adding to the previous text, or of simply over-writing it by typing.
new JTextField("Click & Type Web Address e.g. http://www.google.com");
Maybe you want the Text Prompt, which doesn't actually store any text in the text field. It just gives the user a hint what the text field is for.
This is beneficial so that you don't generate DocumentEvents etc., since you are not actually changing the Document.
Add a mouseListener instead of your actionListener method.
addressBar.addMouseListener(new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent e){
addressBar.setText("");
}
Description of the problem: I have a JFrame, inside this JFrame there is a JPanel with a button, when I press the button an action listener change the current JPanel with a new JPanel, which contains other two JPanels, those two have an inputMap that when the user press the key "up" make something on both of them. The problem is: when I change the JPanel with the new one the "up" key won't do anything.
Here is the code: is a SSCCE, so you just have to copy and paste to see what it does.
This modified code comes from another question that I "solved" sometimes ago. How to make two JPanels listen to the same event?
(the code is in the answer that I selected).
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Arrays;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
public class TwoPanelsTest extends JFrame {
private static MyPanel one = new MyPanel("One");
private static MyPanel two = new MyPanel("Two");
private static List<MyPanel> list = Arrays.asList(one, two);
private PanelsController panelsController;
public TwoPanelsTest() {
super("TwoPanelsTest");
panelsController= new PanelsController(this);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(400,400);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
private static class MyPanel extends JPanel {
private String string = " will be updated though its action.";
private Action action = new UpdateAction(this);
private String name;
private JLabel label;
public MyPanel(String name) {
this.name = name;
this.label = new JLabel(name + string, JLabel.CENTER);
this.setLayout(new GridLayout());
this.setFocusable(true);
this.add(label);
}
public Action getAction() {
return action;
}
private void update() {
label.setText(name + ": " + System.nanoTime());
}
private static class UpdateAction extends AbstractAction {
private MyPanel panel;
public UpdateAction(MyPanel panel) {
this.panel = panel;
}
#Override
public void actionPerformed(ActionEvent ae) {
panel.update();
}
}
}//MyPanel
private static class ButtonPanel extends JPanel{
private JButton button ;
private PanelsController panelsController;
public ButtonPanel(PanelsController panelsController){
this.panelsController=panelsController;
button = new JButton("Button");
button.setActionCommand("buttonPressed");
button.addActionListener(this.panelsController);
this.setFocusable(true);
add(button);
}
}//ButtonPanel
private static class PanelsController implements ActionListener {
private TwoPanelsTest twoPanelsTest;
public PanelsController(TwoPanelsTest twoPanelsTest){
this.twoPanelsTest=twoPanelsTest;
this.twoPanelsTest.getContentPane().add(new ButtonPanel(this));
}
#Override
public void actionPerformed(ActionEvent ae) {
if (ae.getActionCommand().equals("buttonPressed")){
twoPanelsTest.getContentPane().removeAll();
twoPanelsTest.getContentPane().invalidate();
JPanel panel = new JPanel(new GridLayout(0, 1, 10, 10));
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
panel.add(one);
panel.add(two);
panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
panel.getActionMap().put("up", new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
for (MyPanel panel : list) {
panel.getAction().actionPerformed(e);
}
}
});
twoPanelsTest.getContentPane().add(panel);
twoPanelsTest.validate();
twoPanelsTest.repaint();
}
}//ActionPerformed
}//PanelsController
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
TwoPanelsTest t = new TwoPanelsTest();
}
});
}
}
Well, its pretty simple - if you have those two panels without any components inside and want them to listen the hotkey use:
panel.getInputMap ( JComponent.WHEN_IN_FOCUSED_WINDOW )
.put ( KeyStroke.getKeyStroke ( KeyEvent.VK_UP, 0 ), "up" );
JComponent.WHEN_IN_FOCUSED_WINDOW instead of JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT.
Otherwise you need to have somthing focused inside the panel so it could catch the key events.
By the way, there is also another way to listen global hotkeys inside Java application windows:
Toolkit.getDefaultToolkit ().addAWTEventListener ( new AWTEventListener ()
{
public void eventDispatched ( AWTEvent event )
{
// All application key events will be passed here
}
}, AWTEvent.KEY_EVENT_MASK );
I am trying to get an internal frame to contain tabbed panes. However, my code does not seem to be loading the panes into the internal frame. I have my code in the java files, called InternalFrame.java and TabbedPaneSample.java. The code for both files is included below. Can anyone show me how to fix the code below so that it loads the tabbed panes when I run InternalFrame.java?
Here is my code:
The code for InternalFrame.java is:
package test;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
public class InternalFrame extends JFrame {
JButton openButton;
JLayeredPane desktop;
JInternalFrame internalFrame;
TabbedPaneSample myTabbedPaneSample = new TabbedPaneSample();
public InternalFrame() {
super("Click button to open internal frame with two panels.");
setSize(500, 400);
openButton = new JButton("Open");
Panel p = new Panel();
p.add(openButton);
add(p, BorderLayout.SOUTH);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
openButton.addActionListener(new OpenListener());
desktop = new JDesktopPane();
desktop.setOpaque(true);
add(desktop, BorderLayout.CENTER);
}
class OpenListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if ((internalFrame == null) || (internalFrame.isClosed())) {
internalFrame = new JInternalFrame("Internal Frame", true, true, true, true);
internalFrame.setBounds(50, 50, 200, 100);
internalFrame.add(myTabbedPaneSample, BorderLayout.CENTER);
internalFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
internalFrame.pack();
internalFrame.setMinimumSize(new Dimension(300, 300));
desktop.add(internalFrame, new Integer(1));
internalFrame.setVisible(true);
}
}
}
public static void main(String args[]) {
InternalFrame myInternalFrame = new InternalFrame();
myInternalFrame.setVisible(true);
}
}
And the code for TabbedPaneSample.java is:
package test;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
public class TabbedPaneSample extends JTabbedPane {
private JTabbedPane tabbedPane = new JTabbedPane();
private ImageIcon closeImage = new ImageIcon("C:/test/shipIcon.gif");
private Dimension closeButtonSize;
private int tabCounter = 0;
public TabbedPaneSample() {
closeButtonSize = new Dimension(closeImage.getIconWidth() + 2, closeImage.getIconHeight() + 2);
}
public void add() {
final JPanel content = new JPanel();
JPanel tab = new JPanel();
tab.setOpaque(false);
JLabel tabLabel = new JLabel("Tab " + (++tabCounter));
JButton tabCloseButton = new JButton(closeImage);
tabCloseButton.setPreferredSize(closeButtonSize);
tabCloseButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int closeTabNumber = tabbedPane.indexOfComponent(content);
tabbedPane.removeTabAt(closeTabNumber);
}
});
tab.add(tabLabel, BorderLayout.WEST);
tab.add(tabCloseButton, BorderLayout.EAST);
this.addTab(null, content);
this.setTabComponentAt(this.getTabCount() - 1, tab);
}
public static void main(String[] args) {
TabbedPaneSample main = new TabbedPaneSample();
main.add();
main.add();
}
}
Here's one approach, shown below. A more flexible approach using Action is referenced here.
Addendum: Reviewing your code, you should let the various layout managers and component preferred sizes do more of the work, as shown. In particular, this.setPreferredSize() is done for demonstration purposes. In a real application, you would restore user size and location preferences.
package overflow;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
/** #see https://stackoverflow.com/posts/6514889 */
public class InternalFrame extends JFrame {
JButton openButton;
JLayeredPane desktop;
JInternalFrame internalFrame;
public InternalFrame() {
super("Click button to open internal frame with two tabs.");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setPreferredSize(new Dimension(400, 400));
openButton = new JButton("Open");
JPanel p = new JPanel();
p.add(openButton);
this.add(p, BorderLayout.SOUTH);
openButton.addActionListener(new OpenListener());
desktop = new JDesktopPane();
this.add(desktop, BorderLayout.CENTER);
this.pack();
this.setLocationRelativeTo(null);
}
class OpenListener implements ActionListener {
private static final int DELTA = 40;
private int offset = DELTA;
public void actionPerformed(ActionEvent e) {
internalFrame = new JInternalFrame(
"Internal Frame", true, true, true, true);
internalFrame.setLocation(offset, offset);
offset += DELTA;
internalFrame.add(createTabbedPane());
desktop.add(internalFrame);
internalFrame.pack();
internalFrame.setVisible(true);
}
}
private JTabbedPane createTabbedPane() {
JTabbedPane jtp = new JTabbedPane();
createTab(jtp, "One");
createTab(jtp, "Two");
return jtp;
}
private void createTab(JTabbedPane jtp, String s) {
jtp.add(s, new JLabel("TabbedPane " + s, JLabel.CENTER));
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
InternalFrame myInternalFrame = new InternalFrame();
myInternalFrame.setVisible(true);
}
});
}
}
First of all, I think Finally, I think you shouldn't use desktop.add(internalFrame, new Integer(1)) but rather desktop.add(internalFrame) instead, the reason is that JDesktopPane uses its layers (it is a JLayeredPane subclass) internally, and I don't think you should play with layers yourself.
Then, following this problem I had once with JInternalFrame, I would advise you call pack() after adding the internal frame to the desktop pane.
Hence, you should try with your OpenListener class looking like this:
class OpenListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if ((internalFrame == null) || (internalFrame.isClosed())) {
internalFrame = new JInternalFrame("Internal Frame", true, true, true, true);
internalFrame.setBounds(50, 50, 200, 100);
internalFrame.add(myTabbedPaneSample, BorderLayout.CENTER);
internalFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// internalFrame.pack();
internalFrame.setMinimumSize(new Dimension(300, 300));
// desktop.add(internalFrame, new Integer(1));
desktop.add(internalFrame);
internalFrame.pack();
internalFrame.setVisible(true);
}
}
}
Besides, I also agree with trashgod comments on Action of course and the simplifying rework he has done on your snippet.
I preferred to create in my Main Frame class (which extends JFrame) the following function:
private void showIntFrame(Class intFrameClass) {
JInternalFrame targetFrame = null;
int xoff = 0, yoff = 0;
for(JInternalFrame jif : jdp.getAllFrames()) {
if(jif.getClass().equals(intFrameClass))
targetFrame = jif;
if(jif.getLocation().x > xoff)
xoff = jif.getLocation().x;
if(jif.getLocation().y > yoff)
yoff = jif.getLocation().y;
}
if(targetFrame == null) {
try {
Constructor<JInternalFrame> c = intFrameClass.getConstructor(MainFrame.class);
targetFrame = c.newInstance(MainFrame.this);
} catch (Exception ex) {
System.err.println("Exception in MainFrame.showIntFrame() while creating new JInternalFrame instance. " + ex.getLocalizedMessage());
ex.printStackTrace();
return;
}
jdp.add(targetFrame);
targetFrame.setLocation(xoff + 30, yoff + 30);
}
targetFrame.setVisible(true);
try {
targetFrame.setSelected(true);
} catch (PropertyVetoException ex) {
System.err.println("PropertyVetoException in MainFrame.showIntFrame() while activating JInternalFrame instance. " + ex.getLocalizedMessage());
}
}
Here jdp is instance of JDesktopPane, which previously was set as ContentPane of my main JFrame.
Because my programs often contain numbers of different classes, inherited from JInternalFrame, it is easier to call this function from event handlers to show new subclass of JInternalFrame.
Every subclass of JInternalFrame in my programs have one constructor with one parameter - MainFrame (main JFrame).
I have one JFrame that's not actively rendered, a la standard basic Swing applications, which I need to launch another JFrame when a button is clicked. The second JFrame is actively rendered using Swing's BufferStrategy, and runs on its own independently - however, when I call it from the other JFrame's ActionPerformed both JFrames freeze.
I know there are complications in using Swing to accomplish this kind of behavior - how can I get around them?
You might be able to adapt this Swing based Launcher that uses
ProcessBuilder to run programs in a separate JVM.
package gui;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
/**
* #see http://stackoverflow.com/a/5696404/230513
*/
public class Launcher extends JPanel implements Runnable {
private final JLabel label = new JLabel();
private final JButton launch = new JButton();
ProcessBuilder pb = new ProcessBuilder(
"java", "-cp", "build/classes", "gui.Launcher$DialogTest");
private volatile Process proc;
public static void main(String[] args) {
EventQueue.invokeLater(new Launcher()::createGUI);
}
private void createGUI() {
final JFrame frame = new JFrame();
frame.setLayout(new GridLayout(0, 1));
frame.add(new Launcher());
frame.add(new Launcher());
frame.add(new Launcher());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public Launcher() {
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
this.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
launch.setAlignmentX(0.5f);
label.setAlignmentX(0.5f);
launch.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (proc == null) {
launch.setText("Terminate");
label.setText("Status: run");
new Thread(Launcher.this).start();
} else {
proc.destroy();
reset();
}
}
});
this.add(launch);
this.add(label);
reset();
}
#Override
public void run() {
try {
proc = pb.start();
proc.waitFor();
} catch (IOException | InterruptedException ex) {
ex.printStackTrace(System.err);
}
EventQueue.invokeLater(this::reset);
}
private void reset() {
proc = null;
launch.setText("Launch");
label.setText("Status: idle");
}
private static class DialogTest {
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JOptionPane.showMessageDialog(null, "Running",
"Test", JOptionPane.INFORMATION_MESSAGE);
System.exit(0);
});
}
}
}
Updated to Java 8 at the author's request.