I've created a Swing application with several JInternalFrames which gets added to a JDesktopPane on the event of a mouse click. I want only one instance of the same Internal frame to be present on the DesktopPane. I dont want the same frame to appear twice when the user opens the frame..
The simple solution to your problem is to create an HashMap<String,JInternalFrame>. The key will be the title of that JInternalFrame and value will be the object of that JInternalframe opened currently.Save the (key,value) pair in HashMap when the internal frame is opened first time. Disable the close button for all JInternalFrame window , so that user can't dispose the displayed JInternalFrame window. Register esc key to each JInternalFrame object , so that when esc button of keyboard is pressed the currently display JInternalFrame is minimized on the DesktopPane.Now When you click on menu item to open that same internal frame, check if the title of that JInternalFrame is existing in that HashMap askey. If it exists then retrieve the value for that key and refer it by JInternalFrame variable and then restore the same on DesktopPane. If the corresponding entry of title doesn't exist in that HashMap , create a new JInternalFrame object, make an entry for same in the HasMap and display it.
Note: Whatever I have posted here is the solution for the situation where
you can have many types of JInternalFrame each having unique
different functionality, and you want to keep only one instance of
each of those JInternalFrame.
Here is may sample code. hope this help.
Menu action to call internal frame in main application where JdesktopPane in it.
private void YourJinternalFrameMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
YourJinternalFrame nw = YourJinternalFrame.getInstance();
nw.pack();
//usefull part for you.. if open shows, if not creates new one
if (nw.isVisible()) {
} else {
desktopPane.add(nw);
nw.setVisible(true);
}
try {
nw.setMaximum(true);
} catch (PropertyVetoException ex) {
Logger.getLogger(MainApplication.class.getName()).log(Level.SEVERE, null, ex);
}
}
put this inside of your YourJinternalFrame
private static YourJinternalFrame myInstance;
public static YourJinternalFrame getInstance() {
if (myInstance == null) {
myInstance = new YourJinternalFrame();
}
return myInstance;
Try this simple code :
YourJinternalFrame nw = new YourJinternalFrame();
private void YourJinternalFrameMenuItemActionPerformed(java.awt.event.ActionEvent evt) {
if(!nw.isVisible()){
YourJDesktopPane.add(nw);
nw.setVisible(true);
}
}
Try this simple code
take class variable chk and set equal to 0
then call jframe method
componentremoved
in this set chk =0 again
and if you call your internal frame set
chk =1
and compare chk on calling internal wheather it is zero or not
thats all
I went for a different solution:
final JInternalFrame[] frames = desktopPane.getAllFrames();
if( !Arrays.asList(frames).contains(loginFrame) ) {
loginFrame = new LoginFrame();
desktopPane.add(loginFrame);
loginFrame.setVisible(true);
}
This worked for me (checking for the class name):
final JInternalFrame[] frames = desktopPane.getAllFrames();
LoginFrame loginFrame = new LoginFrame();
if( !Arrays.asList(frames).toString().contains("LoginFrame") ) {
desktopPane.add(loginFrame);
loginFrame.setVisible(true);
loginFrame.validate();
}
Related
I am adding to an existing codebase using the Netbeans Platform (14) and its GUI builder to display user selected data to create an output file. The user selects the inputs, then selects to generate the file using a default file name. I want to interrupt the process with a dialog presenting the user with a summary of what they entered, a TextField containing the default file name and the OK - Cancel buttons. I created a DialogDisplayer configured by a DialogDescriptor containing a JPanel which contains the summary info and file name JTextField. This all works, I see the summary data, am able to modify the file name but selecting the OK or Cancel doesn't close the window. Only the X in the upper right will close it.
My actionPerformed() method gets called and exercises the code appropriate to the selected button, but just can't figure out how to close the window from there. I tried setting the closing options to null (dd.setClosingOptions(null);) which the API says causes all action to close the window. No dice.
I don't see a method to call to close the DialogDisplayer window in the API.
I originally thought of using a JDialog but it requires a Frame, which I can't figure out how to get from a org.netbeans.spi.project.ActionProvider, the enclosing class that initiates the request. I have used Swing for more years than I care to admit (since java 1.1) but the Netbeans Platform framework is new to me.
Here is my code:
private class FileNameDialog extends JPanel implements ActionListener
{
private final JTextField fileNameField = new JTextField(50);
private final JLabel fileNameLabel = new JLabel("File Name");
private final JLabel infoLabel = new JLabel();
private final JPanel entryPanel = new JPanel(new FlowLayout());
public FileNameDialog(String fileName, String info)
{
infoLabel.setText(info);
fileNameField.setText(fileName);
setLayout(new BorderLayout());
entryPanel.add(fileNameLabel);
entryPanel.add(fileNameField);
add(BorderLayout.CENTER, infoLabel);
add(BorderLayout.PAGE_END, entryPanel);
}
#Override
public void actionPerformed(ActionEvent e)
{
if (e.getActionCommand().equals(OK_BUTTON))
{
//Replace the file name with what was entered and move on
abort = false; //Global field in enclosing class
logger.log(Level.INFO, "Setting abort to FALSE for {0}",
fileNameField.getText());
}
else if (e.getActionCommand().equals(CANCEL_BUTTON))
{
abort = true; //Global field in enclosing class
logger.log(Level.INFO, "Setting abort to TRUE");
}
//Close the Dialog Window Here (somehow)
}
}
/**
* Request text entry from the user. Currently used for displaying the
* file name and allowing the user to update it. This is the entry point
* for all this code.
* #param info summary text
* #param title window title
* #return the user entered String
*/
private String userRequestDialog(String info, String title, String fileName)
{
FileNameDialog fileNameDialog = new FileNameDialog(fileName, info);
Object [] options = { new JButton ("OK"),
new JButton ("Cancel")};
DialogDescriptor dd = new DialogDescriptor (fileNameDialog,
title,
true,
options,
null,
DialogDescriptor.DEFAULT_ALIGN,
null,
fileNameDialog);
DialogDisplayer.getDefault().notify(dd); //Display the window
dd.setClosingOptions(null); //Doesn't seem to have any effect
return fileNameDialog.fileNameField.getText(); //FileName to use as process continues
}
Just for giggles, I tried Object frame = lookup.lookup(JFrame.class); but that comes back as null.
#jjazzboss - You had the answer that solved my problem and you should get the credit.
Though it technically didn't answer the question, it allowed me to replace the Netbeans DialogDisplayer with a JOptionPane as in below. I also tried a CustomDialog modeled after the one in https://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html, but the OK and Cancel buttons still didn't close it. I suspect that something in Netbeans is stealing those events because a breakpoint in the listener never got hit (or I screwed up the code).
boolean cancelled = false;
Frame frame = WindowManager.getDefault().getMainWindow();
while (!cancelled)
{
String newFileName = JOptionPane.showInputDialog(frame, info, fileName);
if (newFileName == null) //OK was not selected
{
return null;
}
else if (isValidFileName(newFileName))
{
return newFileName;
}
else
{
JOptionPane.showMessageDialog(
frame,
"Sorry, \"" + newFileName + "\" "
+ "isn't a valid file name.\n"
+ "Please Try again",
"Bad File Name",
JOptionPane.ERROR_MESSAGE);
}
}
public JoinChatClient(String serverAddress, String chatName)
{
chatWindow.getContentPane().add(sendButton, "South");
chatWindow.getContentPane().add(splitPane, "Center");
chatWindow.setSize(800,500);
sendButton.addActionListener(this);
chatWindow.setTitle("Chat Room");
chatWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
splitPane.setDividerLocation(350);
sendButton.setBackground(Color.gray);
sendButton.setForeground(Color.red);
outChatTextArea.setEditable(false);
inChatTextArea.setFont (new Font("default",Font.ITALIC,20));
outChatTextArea.setFont(new Font("default",Font.BOLD,20));
inChatTextArea.setLineWrap(true);
outChatTextArea.setLineWrap(true);
inChatTextArea.setWrapStyleWord(true);
outChatTextArea.setWrapStyleWord(true);
inChatTextArea.setText("Enter text to be sent here.");
outChatTextArea.setText("You can move the separator bar!");
inChatTextArea.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
if(inChatTextArea.getText().equals("Enter text to be sent here."))
{
inChatTextArea.setText("");
inChatTextArea.setFont(new Font("default",Font.BOLD,20));
}
}
public void focusLost(FocusEvent e) {
if(inChatTextArea.getText().isEmpty())
{
inChatTextArea.setFont (new Font("default",Font.ITALIC,20));
inChatTextArea.setText("Enter text to be sent here.");
}
}
});
chatWindow.getRootPane().setDefaultButton(sendButton);
chatWindow.setVisible(true);
}
I've looked over all the threads I could find concerning this, and I cannot figure out why hitting ENTER doesn't activate the actionPerformed method attached to sendButton. Is it because the text field has a FocusListener?
Things I've tried:
changing the statement to target the specific text field (inChatTextArea)
moved the setVisible statement to the end
targeted different parts of the GUI when hitting enter
Bear in mind I've only included the code that builds the GUI in an attempt to waste less of your time.
What I want: Ideally, I want to keep my FocusListener (or something like it) so that I can display the "text field hint." I would like to be able to hit ENTER to send the user's text while the inChatTextArea field is focused.
If a component on the JFrame has focus, and can accept an enter key press, such as one of the JTextAreas, then the enter presses will go to that component and not to the default button. For the default button to work, then the JFrame or the button or some other component that does not accept enter key presses, needs to have focus. I'm guessing that one of your JTextAreas has stolen the focus, and that this is messing you up.
This question is old, but I found it when having the same issue. So I hope others might find it useful.
I figured out that getRootPane() will return null if the component is trying to access the root pane too early, e.g. under construction of the component.
Hence, I propose to use SwingUtilities.invoke(Runnable) to postpone setting the default button on the root pane, and also to request the focus to the button.
So this method could be a helper method on a class to extend from:
protected void setDefaultButton(JButton button) {
// Uses invoke later, as getRootPane() might return null if the method is called under construction
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JRootPane rootPane = getRootPane();
if (rootPane != null) {
rootPane.setDefaultButton(button);
}
button.requestFocus(); // set the focus on the button
}
});
}
I have been designing a Swing-based tabletop RPG program to facilitate text-based roleplay with GUI control elements.
To facilitate this, each running client gets a main desktop ("GM Desktop" on the hosting client and "Player Desktop" on the remote clients) with all of the important JFrames. Additionally, both GM and Players can open "Perspective Desktops" for characters, providing them with a separate JDesktopPane that contains the "Role Play Chat Window" that gives that character's perspective, along with additional JInternalFrames such as the "Character Sheet Window", etc.
The user navigates between desktops using a JTabbedPane.
The issue that I am having is that SOME of the windows I want to be able to move between desktops. For example, if the OOC (Out-of-Character) Chat receives a message while the user is in a Perspective Desktop, I want there to be an option for the OOC Chat Window to automatically relocate to the current desktop so the user sees the message immediately. Similarly I want the player to be able to "call" certain windows into the current desktop using the menu bar.
However, when I attempt to move a JInternalFrame from one JDesktopPane to another, I receive an exception.
com.finnickslab.textroleplayonline.exceptions.CommandEventHandlingException
An exception was thrown during command handling. CommandEvent type: UI_OOC_CHAT (26).
Cause Exception: java.lang.IllegalArgumentException
illegal component position
java.awt.Container.addImpl(Unknown Source)
javax.swing.JLayeredPane.addImpl(Unknown Source)
javax.swing.JDesktopPane.addImpl(Unknown Source)
java.awt.Container.add(Unknown Source)
com.finnickslab.textroleplayonline.ui.GameDesktop.receiveTransfer(GameDesktop.java:80)
com.finnickslab.textroleplayonline.ui.GameDesktop.access$0(GameDesktop.java:74)
com.finnickslab.textroleplayonline.ui.GameDesktop$2.run(GameDesktop.java:69)
com.finnickslab.textroleplayonline.ui.UI.invokeEvent(UI.java:818)
com.finnickslab.textroleplayonline.ui.GameDesktop.transfer(GameDesktop.java:62)
com.finnickslab.textroleplayonline.ui.UI$HostCommandHandler.handle(UI.java:605)
com.finnickslab.textroleplayonline.comm.Server$3.run(Server.java:324)
All JInternalFrames in my program descend from the same subclass of JInternalFrame ("InternalWindow").
The exception makes it look a little convoluted but it boils down to calling JDesktopPane.remove(JInternalFrame) then JDesktopPane.add(JInternalFrame).
And then I receive that exception as soon as the "add" method is called on GameDesktop line 80.
/**
* Transfers the specified InternalWindow from this GameDesktop to
* the specified GameDesktop. Use this method to prevent
* automatic removal of listeners performed with the
* {#link GameDesktop.remove(InternalWindow)} method.
*/
public synchronized void transfer(
final InternalWindow window,
final GameDesktop gd) {
final GameDesktop desktop = this;
contents.remove(window);
UI.invokeEvent(new Runnable() {
#Override
public void run() {
desktop.remove((JInternalFrame) window);
desktop.validate();
desktop.repaint();
gd.receiveTransfer(window);
}
});
}
private synchronized void receiveTransfer(InternalWindow window) {
contents.add(window);
window.changeDesktop(this);
window.center();
this.add((JInternalFrame) window); // LINE 80
this.validate();
this.repaint();
window.resetPosition();
}
The "UI.invokeEvent(Runnable)" method is a convenience method I wrote for SwingUtilities.invokeAndWait(Runnable). It checks to see if the current thread is the EDT and, if it is, executes the run() method immediately. Otherwise, it uses invokeAndWait(Runnable) to schedule the runnable on the EDT.
Any ideas of how to fix this problem would be appreciated.
EDIT:
All my research on this error suggests that it has something to do with the Z-axis position of the component. I tried changing the add call to specify the z position
super.add(window, getComponentCount());
but no change. Still getting the same IllegalArgumentException.
See if you get the same error when running this. If not, the problem is not with switching the parent of the internal frame, it's with the synchronization.
public class IFSwitch extends JDesktopPane {
final JDesktopPane pane1 = this;
public IFSwitch() {
JFrame frame1 = new JFrame("Frame1");
JFrame frame2 = new JFrame("Frame2");
// JDesktopPane pane1 = new JDesktopPane();
JDesktopPane pane2 = new JDesktopPane();
final JInternalFrame if1 = new JInternalFrame();
frame1.add(pane1);
frame2.add(pane2);
pane1.add(if1);
if1.setBounds(10, 10, 100, 100);
frame1.setBounds(100, 100, 200, 200);
frame2.setBounds(500, 500, 200, 200);
frame1.setVisible(true);
frame2.setVisible(true);
if1.setVisible(true);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
pane2.add(if1);
pane1.remove(if1); // You don't even need this line.
pane1.repaint();
}
public static void main(String[] args) {
new IFSwitch();
}
}
I know, that this question appears quite frequently in SO like here:
but I would like to present some very specific example... I'm simply not sure if I make things right.
I've got a JDialog in which I can type some values, select some checkboxes... whatever...
I've got also some Response object created in MyDialog which represents the MyDialog's "answer".
In JFrame which calls/creates JDialog:
MyDialog d = new MyDialog(this, ...);
d.showDialog();
// After MyDialog is closed (it's modal):
MyDialog.Response dialogResponse = d.getDialogResponse();
// Do something with response...
In Dialog (dialog can be closed by clicking "Save" button):
btnSave.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dialogResponse = prepareResponse(); // prepares response on the basis of some data introduced by a user; dialogResponse is called from JFrame after Dialog is closed
setVisible(false);
dispose(); // <-- Important
}
});
My question is:
This solution works, I mean, the line MyDialog.Response dialogResponse = d.getDialogResponse(); returns proper values, but...
if I close the dialog using dispose(), all dialog's resources can be garbage collected (don't have to... hard to predict, am I right?). So is it correct to retrieve my dialog's response it that way... Maybe in this case I should write only setVisible(false); without dispose().
Quoted from the Javadocs:
The Window and its subcomponents can be made displayable again by rebuilding the native resources with a subsequent call to pack or show. The states of the recreated Window and its subcomponents will be identical to the states of these objects at the point where the Window was disposed (not accounting for additional modifications between those actions).
So, your Response will be kept. All dispose() does is releasing the native screen resources, other members aren't marked for garbage collection.
Also, if you want to be extra sure, you could just call dispose() right after you retrieved your response object.
if I close the dialog using dispose(), all dialog's resources can be
garbage collected (don't have to... hard to predict, am I right?). So
is it correct to retrieve my dialog's response it that way... Maybe in
this case I should write only setVisible(false); without dispose().
not true that something is GC'ed only non_important value for Graphics/2D
there isn't some reason to create this Object on runtime, re_use this Object
why you don't use class variables (private static or public static) and use a factory method
//it can be an object too public static Object getResponseValue()
public static Integer getResponseValue(){
myclassContainer container = new myclassContainer(someparent,modal).setvisible(true)
return Myfieldvalue
}
private static int Myfielvalue;
}
dialog.add(BorderLayout.CENTER, tree_tmp);
JButton confirm = new JButton("YES");
confirm.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
confirm.setActionCommand("kkk");
dialog.setVisible(false);
}
});
dialog.add(BorderLayout.SOUTH,confirm);
dialog.setSize(400, 400);
dialog.setVisible(true);
System.out.println(confirm.getActionCommand());
What is the best practice for subscribing to events from another JFrame? For example, I have a "settings" form, and when the user presses okay on the settings form, I want the main form to know about this so it can retrieve the settings.
Thanks.
Here is my ideal interface:
public void showSettingsButton_Click() {
frmSettings sForm = new sForm(this._currentSettings);
//sForm.btnOkay.Click = okayButtonClicked; // What to do here?
sForm.setVisible(true);
}
public void okayButtonClicked(frmSettings sForm) {
this._currentSettings = sForm.getSettings();
}
Someone publishes an Event, that something has changed, here the settings. A subscriber that registered for this specifig event, gets notified about it and can do his work, here get the settings. This is called publisher/subscriber.
For this you can use Eventbus or implementing something smaller on your own.
One approach is to have only a single JFrame. All the other 'free floating top level containers' could be modal dialogs. Access the the main GUI will be blocked until the current dialog is dismissed, and the code in the main frame can check the settings of the dialog after it is dismissed.
For anyone interested, here is what I ended up going with. I'm not sure if it's the best way, but it is working for my purposes.
// Method called when the "Show Settings" button is pressed from the main JFrame
private void showSettingsButton_Click() {
// Create new settings form and populate with my settings
frmSettings sForm = new frmSettings(this.mySettings);
// Get the "Save" button and register for its click event...
JButton btnSave = sForm.getSaveButton();
btnSave.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent evt) {
SaveSettings(sForm);
}
});
// Show the settings form
sForm.setVisible(true);
}
// Method called whenever the save button is clicked on the settings form
private void SaveSettings(frmSettings sForm) {
// Get the new settings and assign them to the local member
Settings newSettings = sForm.getSettings();
this.mySettings = newSettings;
}
And if, like me, you are coming from a .NET perspective, here is the C# version:
private void showSettingsButton_Click(object sender, EventArgs e)
{
frmSettings sForm = new frmSettings(this.mySettings);
sForm.btnSave += new EventHandler(SaveSettings);
sForm.Show();
}
private void SaveSettings(object sender, EventArgs e)
{
frmSettings sForm = (frmSettings)sender; // This isn't the exact cast you need..
Settings newSettings = sForm.Settings;
this.mySettings = newSettings;
}