I'm pretty new to creating GUIs in Java, so I'm not sure if this is easy or difficult to do. I'm creating a random name chooser, where the user inputs names and then randomly selects some. I am trying to have it save the names entered after the application is closed, and then placed back when it is reopened. I am not sure the best way to go about this; I've looked around a little bit and read a bit about serialization, but it isn't making a lot of sense. Here's my code from NetBeans so far.
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.DefaultListModel;
import sun.applet.Main;
import sun.audio.*;
public class NameChooser extends javax.swing.JFrame {
private ArrayList <Integer> integers;
private Integer index;
private DefaultListModel dlm;
/**
* Creates new form NameChooser
*/
public NameChooser()
{
initComponents();
integers = new ArrayList <Integer>();
dlm = new DefaultListModel();
}
public Integer generateNum()
{
int pings = 0;
do
{
pings = 0;
int temp = (int)(Math.random() * dlm.getSize());
index = new Integer(temp);
for (int k = 0; k < integers.size(); k++)
{
if ((integers.get(k).compareTo(index)) == 0)
{
pings++;
}
}
}
while (pings != 0);
return index;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
selectButton = new javax.swing.JButton();
jScrollPane2 = new javax.swing.JScrollPane();
names = new javax.swing.JList<>();
nameField = new javax.swing.JTextField();
resetButton = new javax.swing.JButton();
removeButton = new javax.swing.JButton();
jMenuBar1 = new javax.swing.JMenuBar();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
selectButton.setFont(new java.awt.Font("Dialog", 1, 18)); // NOI18N
selectButton.setText("Choose Name");
selectButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
selectButtonActionPerformed(evt);
}
});
names.setFixedCellHeight(30);
names.setFixedCellWidth(200);
names.setLayoutOrientation(javax.swing.JList.VERTICAL_WRAP);
jScrollPane2.setViewportView(names);
nameField.setText("Enter Name Here");
nameField.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
nameFieldActionPerformed(evt);
}
});
resetButton.setText("Reset");
resetButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
resetButtonActionPerformed(evt);
}
});
removeButton.setText("Remove");
removeButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
removeButtonActionPerformed(evt);
}
});
setJMenuBar(jMenuBar1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(layout.createSequentialGroup()
.addGap(349, 349, 349)
.addComponent(selectButton, javax.swing.GroupLayout.PREFERRED_SIZE, 197, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(resetButton))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(23, 23, 23)
.addComponent(removeButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(nameField, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE)
.addGap(18, 18, 18)))
.addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 589, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGap(64, 64, 64))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(119, 119, 119)
.addComponent(nameField, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(26, 26, 26)
.addComponent(removeButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(selectButton, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(26, 26, 26))
.addGroup(layout.createSequentialGroup()
.addContainerGap(84, Short.MAX_VALUE)
.addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 418, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(resetButton)
.addGap(40, 40, 40))
);
pack();
}// </editor-fold>
private void selectButtonActionPerformed(java.awt.event.ActionEvent evt) {
integers.add(generateNum());
if (integers.size() <= dlm.getSize())
{
int [] indexes = new int [integers.size()];
for (int i = 0; i < indexes.length; i++)
{
indexes[i] = integers.get(i).intValue();
}
try {
// Open an audio input stream.
File soundFile = new File("C:\\Users\\Oskar\\Desktop\\sound.wav");
AudioInputStream audioIn = AudioSystem.getAudioInputStream(soundFile);
// Get a sound clip resource.
Clip clip = AudioSystem.getClip();
// Open audio clip and load samples from the audio input stream.
clip.open(audioIn);
clip.start();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
//playSound();
names.setSelectedIndices(indexes);
}
}
private void resetButtonActionPerformed(java.awt.event.ActionEvent evt) {
integers.clear();
int[]indexes = new int[0];
names.setSelectedIndices(indexes);
}
private void nameFieldActionPerformed(java.awt.event.ActionEvent evt) {
//Add Name
int size = nameField.getDocument().getLength();
if (size <= 0)
return;
dlm.addElement(nameField.getText());
nameField.setText("");
names.setModel(dlm);
}
private void removeButtonActionPerformed(java.awt.event.ActionEvent evt) {
if (names.getSelectedIndex() != -1)
{
dlm.remove(names.getSelectedIndex());
}
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(NameChooser.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(NameChooser.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(NameChooser.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(NameChooser.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NameChooser().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JMenuBar jMenuBar1;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JTextField nameField;
private javax.swing.JList<String> names;
private javax.swing.JButton removeButton;
private javax.swing.JButton resetButton;
private javax.swing.JButton selectButton;
// End of variables declaration
}
Could I just make an array or arraylist containing the entered names, somehow save that to a file, then load that file upon running the program to import the names? Or possibly just save the state of the jList? Any help is appreciated.
It is not possible to serialize the state of a Java GUI, because many GUI objects are not serializable.
The JList class is declared as Serializable, so you may be able to serialize it. (It depends on the types of the elements in the list. They also have to be serializable.)
It is theoretically possible to write code that will traverse a GUI data structures, extract the state that needs to be saved into a serializable data structure, and then serialize it. Then you need code to do the reverse; i.e. rebuild / repopulate the GUI from the saved state. (But I suspect you would be better off dealing with this in a different way; e.g. using a custom "preferences" mechanism implemented using properties files or similar.)
However, your aim is to persist the data that you are displaying and updating in the GUI, it is better to do this at the "model" level. Depending on the nature of the model, and the requirements for handling the data, there are other alternatives to object serialization that are:
more efficient,
more scalable,
more resistant to data loss; e.g. when an application crashes,
more able to cope with evolution of the application, and
able to be accessed from outside of Java.
Have a look at java.util.prefs.Preferences. When your app closes, you can do something like...
public void savePreferences() {
Preferences preferences = Preferences.userNodeForPackage(NameChooser.class);
preferences.put("names", "name1, name2, name3");
}
You'll have to extract the names from JList and convert it to a comma delimited string (use StringBuilder). You should be able to get it using JList.getModel. Then when your app loads...
public void loadPreferences() {
Preferences preferences = Preferences.userNodeForPackage(NameChooser.class);
namesAsString = preferences.get("names", null);
}
String.split the namesAsString and whack it back in your JList. Make sense? You got a NullPointerException because I bet you just copy pasted the code. Here's a more simple example:
package example;
import java.util.Date;
import java.util.prefs.Preferences;
public class Example {
public static void main(String[] args) {
Preferences pref = Preferences.userNodeForPackage(Example.class);
String namesAsString = pref.get("names", "empty");
// on first run, this will be empty because you have not saved anything yet
// on succeeding runs, you should see something like:
// Names in preferences: name1Mon May 07 07:15:46 BST 2018, name2Mon May 07 07:15:46 BST 2018
System.out.println("Names in preferences: " + namesAsString);
// simulating new name every time this is run, hence the date
String name1 = "name1" + new Date();
String name2 = "name2" + new Date();
pref.put("names", name1 + ", " + name2);
}
}
You can make a use of Database if you would like to in order to maintain your state. But seems like, just for tiny thing maintaining a database would be costly.
Rather save them in a flat file .txt file and define your own delimiter.
For example:
Insert each record in a new line.
Each value in a record is separated by a pipe |.
Sample of file data:
First Name | Second Name | Anything
First Name 2 | Second Name 2 | Anything else
Then once your application loads up, check for the existence of this file and then read this file. You will need to create your parser which understands your file syntax. And then populate your GUI as per these data (if any).
Update the file if your application requires so
Another approach would be to Create a java class "State" (normal POJO) and then serialize it and save it in your file. When the application loads up, then deserialize it and use in your application.
The problem is:
Overhead of serializing and de-serializing and storing the file
Ensure when object upgrades then you need to maintain old fields (legacy) else your deserializing won't work (common problem of serialization/deserialization).
Google topic around this for more details.
Related
I have four small class: one extends from JFrame and has GUI form, second — extends from him and contains button work logic. Third class call second's class method, when second — call him :)). My problem in second method in second class: button can't enable! I click — it disabled, but, when calling method enableButton — nothing do!
First class:
public class ClassParent extends JFrame {
protected JButton button;
private JPanel mainJPanel;
public ClassParent() {
super("Window");
setContentPane(mainJPanel);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public void showWindow() {
setVisible(true);
}
}
Second class:
public class ClassChildren extends ClassParent {
private CallerClass callerClass;
public ClassChildren(CallerClass callerClass) {
super();
this.callerClass = callerClass;
callerClass.setClassChildren(this);
button.addActionListener(a -> {
callerClass.callMe();
button.setEnabled(false);
});
}
public void enableButton() {
button.setEnabled(true);
}
}
Third class:
public class CallerClass {
private ClassChildren classChildren;
public void setClassChildren(ClassChildren classChildren) {
this.classChildren = classChildren;
}
public void callMe() {
classChildren.enableButton();
}
}
Main class:
public class Main {
public static void main(String[] args) {
new ClassChildren(new CallerClass()).showWindow();
}
}
And GUI form photo (I can't find code, other than open it in notepad :)):
Why is this happening and how fix it?
Apparently the OP has solved his problem, but I think this is an interesting and common-enough problem, so I've created a Minimal, Complete and Verifiable Example of what my recommended approach would be, for future reference.
You can check it out below, or you can get the full project from the GitHub repository.
(Reviews, suggestions, revisions and feedback are also welcome!)
Main JFrame:
/**
* #author Rodrigo Legendre Lima Rodrigues (AKA ArchR / AlmightyR)
* <rodrigolegendre.developer#gmail.com>
*/
public class Main extends javax.swing.JFrame {
/**
* A public method so we can enable/disable state from outside the class
* (while keeping the components encapsulated).
*
* #param enabled The input state the components should assume.
*/
public void setInputState(boolean enabled) {
this.startProcessButton.setEnabled(enabled);
}
/**
* Creates new form Main
*/
public Main() {
initComponents();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
startProcessButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("Primary Frame");
startProcessButton.setText("Process");
startProcessButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
startProcessButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(startProcessButton, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE)
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(startProcessButton)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
#SuppressWarnings("Convert2Lambda")
private void startProcessButtonActionPerformed(java.awt.event.ActionEvent evt) {
//We need a non-annonymous reference for this frame to use within our annonymous 'run()'.
Main main = this;
//Here is were we disable input for (the components of) this frame before running the secondary frame.
this.setInputState(false);
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Secondary(main).setVisible(true);
}
});
}
/**
* #param args the command line arguments
*/
#SuppressWarnings("Convert2Lambda")
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Main().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton startProcessButton;
// End of variables declaration
}
Secondary JFrame:
/**
*
* #author Rodrigo Legendre Lima Rodrigues (AKA ArchR)
* <rodrigolegendre.developer#gmail.com>
*/
public class Secondary extends javax.swing.JFrame {
/**
* A variable to hold a reference to the main frame. We need this to enable
* the input of main again after this frame's work is done.
*/
private Main main;
/**
* A self-reference to this frame. We need this to hide the frame from
* within the worker, after it's job is done.
*/
private Secondary secondary;
/**
* A SwingWorker executes a process without interfering with the UI's
* execution, which could otherwise cause delays or complete "locking" of
* the visual and input processes.
*/
SwingWorker<Integer, Integer> swingWorker = new SwingWorker<Integer, Integer>() {
#Override
#SuppressWarnings("SleepWhileInLoop")
protected Integer doInBackground() throws Exception {
//Execute the process...
for (int i = 0; i <= 100; i++) {
progressBar.setValue(i);
Thread.sleep(100);
}
//We handle reactivating the main frame's inputs on the closing event,
//to make sure they get enabled after this frame is closed,
//regardless of sucess, cancelation or failure.
//We close and dispose of the secondary frame.
//Note: We have set default close behavior for this frame to be disposing, so we simply send it a closing event.
secondary.dispatchEvent(new WindowEvent(secondary, WindowEvent.WINDOW_CLOSING));
//Alternatively:
//main.setInputState(true);
//secondary.setVisible(false);
//secondary.dispose();
return 100;
}
};
/**
* In order to start the process while keeping all related code contained
* within this class, we make it listen to it's own WindowOpened event.
*
* In order to avoid calling an overridable method ('addListener()') from
* the constructor, which could be "forgotten" on extensions, we create a
* private method to initialize all self-listeners.
*/
private void initSelfListeners() {
WindowListener taskStarterWindowListener = new WindowListener() {
#Override
public void windowOpened(WindowEvent e) {
//This starts the process when the window opens.
System.out.println("Performing task...");
swingWorker.execute();
}
//<editor-fold defaultstate="collapsed" desc="UNUSED EVENTS/METHODS">
#Override
public void windowClosing(WindowEvent e) {
//Do nothing.
}
#Override
public void windowClosed(WindowEvent e) {
//Do nothing.
}
#Override
public void windowIconified(WindowEvent e) {
//Do nothing.
}
#Override
public void windowDeiconified(WindowEvent e) {
//Do nothing.
}
#Override
public void windowActivated(WindowEvent e) {
//Do nothing.
}
#Override
public void windowDeactivated(WindowEvent e) {
//Do nothing.
}
//</editor-fold>
};
//Here is where the magic happens. We make (a listener within) the frame start listening to the frame's own WindowOpened event.
this.addWindowListener(taskStarterWindowListener);
}
/**
* Creates new form Secondary
*/
#SuppressWarnings("LeakingThisInConstructor")
private Secondary() {
initComponents();
initSelfListeners();
this.secondary = this;
}
public Secondary(Main main) {
this();
this.main = main;
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
processingLabel = new javax.swing.JLabel();
progressBar = new javax.swing.JProgressBar();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setTitle("Secondary Frame");
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent evt) {
formWindowClosing(evt);
}
});
processingLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
processingLabel.setText("Processing...");
progressBar.setStringPainted(true);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(processingLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(progressBar, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(processingLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
private void formWindowClosing(java.awt.event.WindowEvent evt) {
//When the window is closed, we enable the input in the main frame again.
//This is advantageous as it handles most cases in one go...
//The cases were the window closes after the process is complete,
//the cases there the window closes due to cancelation,
//or the cases where it is closed by the user (after an error message) after a failure.
main.setInputState(true);
}
/**
* #param args the command line arguments
*/
#SuppressWarnings("Convert2Lambda")
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(Secondary.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Secondary().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JLabel processingLabel;
private javax.swing.JProgressBar progressBar;
// End of variables declaration
}
Problem was in that I call firstly callMe() and enable buttons and then — I disabled they in listeners......
Hey i have some questions/problems.
I have to create a little program for text editing. The (selected) text should be style. Bold, Italic, Underline, Right- left- center alignment.
It works great. I used the specific StyleEditorKit Actions.
My problem is now that this actions are fired through buttons in a jtoolbar and jmenuitems in a jmenu / jmenubar.
So there are two click elements to set a text bold, two elements to set a text italic and so on.
If one element (e.g. the button in the toolbar) is clicked, the jmenuitem should be selected/activated too.
But how can i realize this?
My idea is to check the selected text (CaretListener is implemented). If the text is bold => set the button and menuitem active.
But how can i get if the selectedText is bold/italic etc?
I think there is a StyledDocument tree with leafs for this stuff. But how can i get this tree? how can i get the leafs?
This are my first steps:
jTextPane1.addCaretListener(new CaretListener() {
#Override
public void caretUpdate(CaretEvent e) {
Highlight[] h = jTextPane1.getHighlighter().getHighlights();
for(int i = 0; i < h.length; i++) {
System.out.println(h[i].getStartOffset());
System.out.println(h[i].getEndOffset());
String selectedText = jTextPane1.getSelectedText();
StyledDocument styleddoc = (StyledDocument) jTextPane1.getDocument();
System.out.println(styleddoc);
}
}
});
But i only get javax.swing.text.DefaultStyledDocument#5098cb76
How can i iterate over the tree and get the leafs / bold or italic elements?
Thank you
how can i get if the selectedText is bold/italic etc?
In your CaretListener you can use:
AttributeSet attributes = jTextPane1.getCharacterAttributes();
System.out.println( attributes.containsAttribute(StyleConstants.Bold, Boolean.TRUE) );
If one element (e.g. the button in the toolbar) is clicked, the jmenuitem should be selected/activated too.
You should be using an Action:
Action bold = new StyledEditorKit.BoldAction();
JButton boldButton = new JButton( bold );
JCheckBoxMenuItem boldMenuItem = new JCheckBoxMenuItem( bold );
When you set the state of an Action, the state of all components using the Action is changed. For example you can make the Action selected or enabled.
my code looks like this now
public void jToolBarInitButtons() {
jTextPane1.addCaretListener(new CaretListener() {
#Override
public void caretUpdate(CaretEvent e) {
StyledDocument styleddoc = (StyledDocument) jTextPane1.getDocument();
AttributeSet attributes = jTextPane1.getCharacterAttributes();
System.out.println("bold " + attributes.containsAttribute(StyleConstants.Bold, Boolean.TRUE));
System.out.println("italic " + attributes.containsAttribute(StyleConstants.Italic, Boolean.TRUE));
}
So there are two click elements to set a text bold, two elements to set a text italic and so on. If one element (e.g. the button in the toolbar) is clicked, the jmenuitem should be selected/activated too. But how can i realize this?
Create both the menu item and the button by passing the same Action to their constructors.
It sounds like you intend show the bold state in the button and menu item, so you’ll probably want to create a JCheckBoxMenuItem and a JToggleButton. When you create the Action, set its SELECTED_KEY to a non-null value, so the buttons will keep it up to date:
action.putValue(Action.SELECTED_KEY, false);
From the Action documentation:
SELECTED_KEY
Components that honor this property only use the value if it is non-null. For example, if you set an Action that has a null value for SELECTED_KEY on a JToggleButton, the JToggleButton will not update it's selected state in any way. Similarly, any time the JToggleButton's selected state changes it will only set the value back on the Action if the Action has a non-null value for SELECTED_KEY. Components that honor this property keep their selected state in sync with this property. When the same Action is used with multiple components, all the components keep their selected state in sync with this property.
Your CaretListener should be as camickr described.
Sorry. This is the whole code:
Update 2: here is the code
public class TestFrame extends javax.swing.JFrame {
/**
* Creates new form TestFrame
*/
public TestFrame() {
initComponents();
initButtons();
}
Action boldAction = new StyledEditorKit.BoldAction();
Action italicAction = new StyledEditorKit.ItalicAction();
Action underlineAction = new StyledEditorKit.UnderlineAction();
public void initButtons() {
JButton boldButton = new JButton(boldAction);
boldButton.setText("bold");
JButton italicButton = new JButton(italicAction);
boldButton.setText("italic");
JButton underlineButton = new JButton(underlineAction);
boldButton.setText("underline");
jToolBar1.add(boldButton);
jToolBar1.add(italicButton);
jToolBar1.add(underlineButton);
jTextPane1.addCaretListener(new CaretListener() {
#Override
public void caretUpdate(CaretEvent e) {
Highlighter.Highlight[] h = jTextPane1.getHighlighter().getHighlights();
for(int i = 0; i < h.length; i++) {
System.out.println("length " + h.length);
System.out.println(h[i].getStartOffset());
System.out.println(h[i].getEndOffset());
String selectedText = jTextPane1.getSelectedText();
StyledDocument styleddoc = (StyledDocument) jTextPane1.getDocument();
AttributeSet attributes = jTextPane1.getCharacterAttributes();
System.out.println("Bold " + attributes.containsAttribute(StyleConstants.Bold, Boolean.TRUE));
System.out.println("Italic " + attributes.containsAttribute("Italic " + StyleConstants.Italic, Boolean.TRUE));
System.out.println("Underline " + attributes.containsAttribute(StyleConstants.Underline, Boolean.TRUE));
}
}
});
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jTextPane1 = new javax.swing.JTextPane();
jToolBar1 = new javax.swing.JToolBar();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jScrollPane1.setViewportView(jTextPane1);
jToolBar1.setRollover(true);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap(116, Short.MAX_VALUE)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 269, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(75, 75, 75))
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 192, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(23, 23, 23)
.addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(14, 14, 14)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 154, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(89, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(TestFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new TestFrame().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextPane jTextPane1;
private javax.swing.JToolBar jToolBar1;
// End of variables declaration
}
I have a java application containing one text-field and I'm using a joystick.
How can I do something in the text-field when a button on the joystick is pressed?
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package op;
import net.java.games.input.Controller;
/**
*
* #author Ahmed
*/
public class Test extends javax.swing.JFrame {
/**
* Creates new form Test
*/
public Test() {
initComponents();
con();
}
private void con(){
JInputJoystick joystick = new JInputJoystick(Controller.Type.STICK);
if( !joystick.isControllerConnected() ){
txt.setText("Not Connected");
}
else
txt.setText(joystick.getControllerType()+" "+joystick.getControllerName()+" Controller Cound!");
if( !joystick.pollController() ) {
txt.setText("Controller disconnected!");
}
// Number of buttons.
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
txt = new javax.swing.JTextField();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(70, 70, 70)
.addComponent(txt, javax.swing.GroupLayout.DEFAULT_SIZE, 242, Short.MAX_VALUE)
.addGap(88, 88, 88))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(122, 122, 122)
.addComponent(txt, javax.swing.GroupLayout.PREFERRED_SIZE, 33, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(145, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
/**
* #param args the command line arguments
*/
// Variables declaration - do not modify
private javax.swing.JTextField txt;
// End of variables declaration
}
Based on the tutorial project here: https://theuzo007.wordpress.com/2013/10/26/joystick-in-java-with-jinput-v2/ it looks like you have to loop and just check things, so
private void con(){
JInputJoystick joystick = new JInputJoystick(Controller.Type.STICK);
while (joystick.isControllerConnected()) {
// Go trough all components of the controller.
Component[] components = joystick.getComponents();
for(int i=0; i < components.length; i++) {
Component component = components[i];
Identifier componentIdentifier = component.getIdentifier();
// Buttons
if(componentIdentifier.getName().matches("^[0-9]*$")){ // If the component identifier name contains only numbers, then this is a button.
// Is button pressed?
if(component.getPollData() != 0.0f) {
txt.setText("Button got pressed!")
}
}
}
// We have to give processor some rest.
try {
Thread.sleep(25);
} catch (InterruptedException ex) {
Logger.getLogger(JoystickTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
txt.setText("Controller not connected");
}
I had some questions earlier regarding this base code which were
solved here but now my issue is that i have to take this code and get
out the result in GUI textArea. What ive done so far is that ive
designed a textArea and a button but now im stuck. I dont know how to
translate that code i used as a base into the GUI and make it possible
to click on the button and display the answers into the textdisplay. I
dont know if i should copy this base code somewhere or do i need to do
totally different thing inside of the GUI? For instance under
jButtonActionPerformed, what do i need to do... im sorry im new to
this and so lost. Ive googled all day but its hard to understand.
Here is the base code :
import java.lang.String;
class Vara {
//Deklarerar variabler
private String name;
private double price;
private int antal;
//tildela konstruktorer för de deklarerade variablerna
public Vara (String name, int antal, double price) {
this.name = name;
this.antal = antal;
this.price = price;
} // slut constructor
public void setName(String name) {
this.name = name; }
public void setPrice (double price) {
this.price = price; }
public void setAntal (int antal) {
this.antal = antal; }
public String getName() {
return this.name;}
public double getPrice() {
return this.price; }
public int getAntal() {
return this.antal; }
}
//testklassen ska stå som en egen klass
class Test {
public static void main(String[] args){
Vara var = new Vara("Banan",5, 12.5);
System.out.println("Namnet är " +var.getName() +" och priset är " +var.getPrice() +" och antalet är "+var.getAntal() );// här slutar system.out
}
}
And here is the beginning of my code in GUI which i havent done anything on so far except creating a textArea and a button.
public class NewJFrame extends javax.swing.JFrame {
/**
* Creates new form NewJFrame
*/
public NewJFrame() {
initComponents();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jTextArea1 = new javax.swing.JTextArea();
jButton1 = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jTextArea1.setColumns(20);
jTextArea1.setRows(5);
jScrollPane1.setViewportView(jTextArea1);
jButton1.setText("jButton1");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap(29, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 213, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(69, 69, 69))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 361, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 231, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(17, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
txtDisplay.setText(null);
txtDisplay.append(String.valueOf(String)+"\n");
// TODO add your handling code here:
}
/**
* #param args the command line arguments
*/
public static void main(String args[]) {
/*
* Set the Nimbus look and feel
*/
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/*
* If Nimbus (introduced in Java SE 6) is not available, stay with the
* default look and feel. For details see
* http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/*
* Create and display the form
*/
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
}
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextArea jTextArea1;
// End of variables declaration
}
in GUI Class make set the modifier to "Public Static" so it can be accessed from other class.
public static javax.swing.JTextArea jTextArea1;
then you can enter Value in this jTextArea1 from other classes. by accessing directly like this
NewJFrame.jTextArea1.append("text to append");
From your question it is not obvious if you want to put in data into your JTextArea or to read the content entered in the JTextArea in order to store it somewhere else. I will answer for both cases.
An elegant way to wire up data and GUI is to insert the data model object (in your case an instance of the class Vara) into a GUI object. E.g. this can be done right at the GUI object creation as shown in the code below. I commented each new line in your code with "// CHANGED: ...".
public class NewJFrame extends javax.swing.JFrame {
// CHANGED: store the model for this GUI
private Vara vara;
/**
* Creates new form NewJFrame
*/
public NewJFrame(Vara vara) { // CHANGED: provide the model for this GUI
this.vara = vara; // CHANGED: store the model for this GUI
initComponents();
// CHANGED: set TextArea content according to the data in the
// provided model object (if this is what you want)
jTextArea1.setText(vara.getName());
}
...
...
...
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
txtDisplay.setText(null);
txtDisplay.append(String.valueOf(String)+"\n");
// CHANGED: read the entered text from the TextArea and store it as the
// new name of the Vara object (if this is what you want to happen when
// the user clicks on the button)
vara.setName(jTextArea1.getText());
}
...
...
...
// Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextArea jTextArea1;
// End of variables declaration
}
Some tips for a better programmer life:
use English everywhere, also in the comments
always name the GUI elements reasonable, e.g. your jButton1 could be btnSave ("btn" stands for Button) and your jTextArea1 could be taVaraName ("ta" stands for TextArea) - this greatly increase readability of your GUI code and makes debugging and maintaining much easier
use Eclipse for Java development, esp. if you want to build GUIs. It comes with a plugin called Eclipse WindowBuilder. This is "a powerful and easy to use bi-directional Java GUI designer", means you can: (1) easily drag-and-drop your GUI elements and get the code automatically generated for you; (2) modify any part of the code and see the drag-and-drop view automatically changing accordingly. It generates much cleaner and often shorter GUI code than the one you posted and lets you modify everything (does not have the "don't modify" parts you have in your code)
Our application displays a 2D view of our data (mainly maps) and then allows the user to change to a 3D view. The 2D and 3D views are generated by custom C++ code that is SWIG'ed into our Swing GUI and wrapped within a JComponent. These JComponents are then displayed within another parent JComponent.
Our problem is that when we change from the 2D to the 3D view and then back to the 2D view, when we resize the window the 2D view does not get resized. The resize events don't get sent to the 2D view.
Our application runs under Linux (Fedora 11). We're running Java version 1.6.0_12.
Here is some sample code in which I've replaced the 2D view and 3D view with two 2 JButtons, that produces the same behaviour. Once you go to 3D and then back to 2D, resizing the window does not cause the 2D view to be resized.
/* TestFrame.java
* Compile with: $ javac TestFrame.java
* Run with: $ java TestFrame
*/
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import javax.swing.JButton;
public class TestFrame extends javax.swing.JFrame {
private boolean mode2D = true;
private JButton view2D = null;
private JButton view3D = null;
private Container parent = null;
public TestFrame() {
initComponents();
containerPanel.setLayout(new BorderLayout());
view2D = new JButton("2D View");
view2D.addComponentListener(new MyListener("2D VIEW"));
containerPanel.add(view2D);
}
private void changerButtonActionPerformed(java.awt.event.ActionEvent evt) {
if (parent == null) {
parent = view2D.getParent();
}
if (mode2D) {
System.out.println("Going from 2D to 3D");
view2D.setVisible(false);
if (view3D != null) {
view3D.setVisible(true);
} else {
view3D = new JButton("3D View");
view3D.addComponentListener(new MyListener("3D VIEW"));
parent.add(view3D);
}
((JButton) evt.getSource()).setText("Change to 2D");
mode2D = false;
} else {
System.out.println("Going from 3D to 2D");
view3D.setVisible(false);
view2D.setVisible(true);
((JButton) evt.getSource()).setText("Change to 3D");
mode2D = true;
}
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new TestFrame().setVisible(true);
}
});
}
private javax.swing.JPanel containerPanel;
private javax.swing.JButton changerButton;
private class MyListener implements ComponentListener {
private String name;
public MyListener(String name) {
this.name = name;
}
#Override
public void componentHidden(ComponentEvent event) {
System.out.println("### [" + name + "] component Hidden");
}
#Override
public void componentResized(ComponentEvent event) {
System.out.println("### [" + name + "] component Resized");
}
#Override
public void componentShown(ComponentEvent event) {
System.out.println("### [" + name + "] component Shown");
}
#Override
public void componentMoved(ComponentEvent event) {
System.out.println("### [" + name + "] component Moved");
}
};
#SuppressWarnings("unchecked")
private void initComponents() {
containerPanel = new javax.swing.JPanel();
changerButton = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
containerPanel.setBorder(new javax.swing.border.MatteBorder(null));
javax.swing.GroupLayout containerPanelLayout = new javax.swing.GroupLayout(containerPanel);
containerPanel.setLayout(containerPanelLayout);
containerPanelLayout.setHorizontalGroup(
containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 374, Short.MAX_VALUE)
);
containerPanelLayout.setVerticalGroup(
containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 239, Short.MAX_VALUE)
);
changerButton.setText("Change to 3D");
changerButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
changerButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(containerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(changerButton))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(containerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(changerButton)
.addContainerGap())
);
pack();
}
}
(My apologies for the Netbeans generated GUI code)
I should mention that when we call parent.remove(view2D) and parent.add(view3D) to change the views the X Windows ID of our 3D view changes and we're unable to get our 3D view back. Therefore parent.remove(view2D) and parent.add(view3D) is not really a solution and we have to call setVisible(false) and setVisible(true) on the JComponents that contain our 2D and 3D views in order to hide and show them.
Any help will be greatly appreciated.
Why don't you use a CardLayout to switch from the 2D to 3D component?
CardLayout is exactly done for this kind of purpose in my understanding.
Another benefit would be that it will simplify your code.
After your remove() and add() methods to change the component, you should call:
parent.revalidate(); //To make the layout manager do its work.
parent.repaint(); //This could be necessary, to suggest a repaint of the panel
Javadoc for JComponent#revalidate() :
Supports deferred automatic layout.
Calls invalidate and then adds this
component's validateRoot to a list of
components that need to be validated.
Validation will occur after all
currently pending events have been
dispatched. In other words after this
method is called, the first
validateRoot (if any) found when
walking up the containment hierarchy
of this component will be validated.
By default, JRootPane, JScrollPane,
and JTextField return true from
isValidateRoot.
This method will automatically be
called on this component when a
property value changes such that size,
location, or internal layout of this
component has been affected. This
automatic updating differs from the
AWT because programs generally no
longer need to invoke validate to get
the contents of the GUI to update.
I've found a solution. You need to add/remove the components from the layout manager:
private void changerButtonActionPerformed(java.awt.event.ActionEvent evt) {
if (parent == null) {
parent = view2D.getParent();
}
LayoutManager layoutMgr = parent.getLayout();
if (mode2D) {
System.out.println("Going from 2D to 3D");
view2D.setVisible(false);
layoutMgr.removeLayoutComponent(view2D);
if (view3D != null) {
view3D.setVisible(true);
if (layoutMgr != null && layoutMgr instanceof LayoutManager2) {
((LayoutManager2) layoutMgr).addLayoutComponent(view3D, null);
}
} else {
view3D = new JButton("3D View");
view3D.addComponentListener(new MyListener("3D VIEW"));
parent.add(view3D);
}
((JButton) evt.getSource()).setText("Change to 2D");
mode2D = false;
} else {
System.out.println("Going from 3D to 2D");
view3D.setVisible(false);
layoutMgr.removeLayoutComponent(view3D);
view2D.setVisible(true);
if (layoutMgr != null && layoutMgr instanceof LayoutManager2) {
((LayoutManager2) layoutMgr).addLayoutComponent(view2D, null);
}
((JButton) evt.getSource()).setText("Change to 3D");
mode2D = true;
}
}