frame.dispose() not working. Possibly an instantiating object problem? - java

I have a game that has a MainUI class, a GameClass and a SettingsClass. The game works fine except when I click "Restart" or "Help" which takes me to another JFrame and then returns back to the MainUI by a click of a button. But, when that happens, the MainUI class does not dispose of itself when it should. I believe it has to do with instantiating the MainUI class again when I leave and come back from settings but I'm but sure how to fix it.
This is the code I'm using to dispose of the MainUI frame and open a new JFrame:
private final JFrame mainFrame;
mainFrame.dispose(); //the mainFrame variable is passed in the constructor since it's trying to dispose of the MainUI
EndingPage endingPage = new EndingPage(); //open ending page
endingPage.setVisible(true);
This is an example of part of the code for one of the buttons in the settings class
restart.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
MainUI.started=false;
mainFrame.dispose();
TitlePage title = new TitlePage();
title.setVisible(true);
}
});
When one of those buttons are clicked, another JFrame is opened accordingly. To go back to the MainUI this is run:
this.dispose();
MainUI main = new MainUI();
main.setVisible(true);
For more clarification, the second code is run when the user clicks the settings button. Then, the last code is run to get back to the JFrame it already was at. When the user wins the first code is run. But the issue is sometimes the mainFrame.dispose(); in the first code does not work. Any help is appreciated! If you need to see other code please tell me! I'm stuck.
EDIT:
This is the MainUI (there is a timer because I want to delay before the action)
package stackoverflowcode;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
public class MainUI extends javax.swing.JFrame {
/**
* Creates new form MainUI
*/
public MainUI() {
initComponents();
GameClass game = new GameClass(this, end);
SettingsClass settings = new SettingsClass(restart, this);
Timer timer;
private javax.swing.JButton end;
private javax.swing.JButton restart;
ActionListener action = new ActionListener(){
#Override
public void actionPerformed(ActionEvent event)
{
game.openEnd();
}
};
timer= new Timer (1000,action);
timer.start();
settings.settings();
}
private void initComponents() {
restart = new javax.swing.JButton();
end = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
restart.setText("SETTINGS");
end.setText("END");
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(151, 151, 151)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(end)
.addComponent(restart))
.addContainerGap(168, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(120, 120, 120)
.addComponent(restart)
.addGap(48, 48, 48)
.addComponent(end)
.addContainerGap(86, Short.MAX_VALUE))
);
pack();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new MainUI().setVisible(true);
}
});
}
}
SettingsClass
package stackoverflowcode;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
public class SettingsClass {
JButton restart;
JFrame mainFrame;
public SettingsClass(JButton restart, JFrame mainFrame){
this.restart=restart;
this.mainFrame=mainFrame;
}
public void settings() {
restart.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
mainFrame.dispose();
TitlePage title = new TitlePage();
title.setVisible(true);
}
});
}
}
TitlePage
package stackoverflowcode;
public class TitlePage extends javax.swing.JFrame {
/**
* Creates new form TitlePage
*/
public TitlePage() {
initComponents();
private javax.swing.JButton Play;
}
private void initComponents() {
Play = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
Play.setText("PLAY");
Play.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
PlayActionPerformed(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()
.addGap(134, 134, 134)
.addComponent(Play)
.addContainerGap(209, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(129, 129, 129)
.addComponent(Play)
.addContainerGap(148, Short.MAX_VALUE))
);
pack();
}
private void PlayActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
this.dispose();
MainUI main = new MainUI();
main.setVisible(true);
}
public static void main(String args[]){
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new TitlePage().setVisible(true);
}
});
}
}
GameClass
package stackoverflowcode;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
public class GameClass {
private final JFrame mainFrame;
private final JButton endButton;
public GameClass(JFrame mainFrame, JButton endButton){
this.mainFrame=mainFrame;
this.endButton=endButton;
}
public void openEnd(){
endButton.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
mainFrame.dispose(); //the mainFrame variable is passed in the constructor since it's trying to dispose of the MainUI
TitlePage endingPage = new TitlePage(); //open title page
endingPage.setVisible(true);
}
});
}
}

Related

java.util.observer with multiple JFrame

I am trying to implement Observer pattern with multiple JFrame instances. However, when notifyObservers() is called, only the last instantiated JFrame instance is updated.
This is my code:
Mall.java
import java.util.ArrayList;
import java.util.Observable;
public class Mall extends Observable{
private ArrayList<String> stores;
public Mall(){
stores = new ArrayList<String>();
}
public void addNewStore(String store){
stores.add(store);
System.out.println(store);
setChanged();
notifyObservers(store);
}
public ArrayList<String> getStores(){
return stores;
}
}
CustomerFrame.java
public class CustomerFrame extends javax.swing.JFrame {
public CustomerFrame() {
initComponents();
}
public CustomerFrame(Mall theMall) {
initComponents();
MallObserver mallObs = new MallObserver();
theMall.addObserver(mallObs);
}
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jList1 = new javax.swing.JList();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jList1.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
jScrollPane1.setViewportView(jList1);
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(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 249, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(141, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 165, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(124, Short.MAX_VALUE))
);
pack();
}
public static javax.swing.JList jList1;
private javax.swing.JScrollPane jScrollPane1;
}
MallObserver.java
import java.util.Observable;
import java.util.Observer;
import javax.swing.DefaultListModel;
public class MallObserver implements Observer{
private Mall mallUpdate;
#Override
public void update(Observable o, Object arg) {
mallUpdate = (Mall) o;
DefaultListModel listModel = new DefaultListModel();
for(int i = 0; i < mallUpdate.getStores().size(); i++)
listModel.addElement(mallUpdate.getStores().get(i));
CustomerFrame.jList1.setModel(listModel);
}
}
AdminFrame.java
public class AdminFrame extends javax.swing.JFrame {
Mall theMall;
public AdminFrame() {
initComponents();
theMall = new Mall();
}
#SuppressWarnings("unchecked")
private void initComponents() {
jTextField1 = new javax.swing.JTextField();
jLabel1 = new javax.swing.JLabel();
jButton1 = new javax.swing.JButton();
jButton2 = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jTextField1.setText("jTextField1");
jLabel1.setText("jLabel1");
jButton1.setText("Add Store");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
jButton2.setText("New Customer");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton2ActionPerformed(evt);
}
});
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(143, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jButton2)
.addComponent(jButton1)
.addGroup(layout.createSequentialGroup()
.addComponent(jLabel1)
.addGap(26, 26, 26)
.addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addGap(138, 138, 138))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(129, 129, 129)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel1))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jButton1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jButton2)
.addContainerGap(88, Short.MAX_VALUE))
);
pack();
}
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
CustomerFrame newCust = new CustomerFrame();
newCust.setVisible(true);
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
theMall.addNewStore(jTextField1.getText());
}
public static void main(String args[]) {
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(AdminFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(AdminFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(AdminFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(AdminFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new AdminFrame().setVisible(true);
}
});
}
private javax.swing.JButton jButton1;
private javax.swing.JButton jButton2;
private javax.swing.JLabel jLabel1;
private javax.swing.JTextField jTextField1;
}
The idea is, when a customer enters the store, the store will open up a new JFrame for the customer. When admin adds a store, all the JFrame CustomerFrame.java will have their list item updated. However, in my case, only the CustomerFrame.java that is last instantiated will get the update while the others remains the same.
The problem above can be reproduced by Opening 2 New Customer and try to Add Store at AdminFrame.java
What is the problem here?
You don't call any methods on thisFrame from within the MallCustomer's update(...) method. Rather than setting the model on storeList (where the heck does that come from?), give CustomerFrame a public method, say called setStoreListModel(ListModel listModel) that you call in update, passing in the storeModel.
i.e.,
public class CustomerFrame extends javax.swing.JFrame {
privarte Mall theMall;
private JList storesList = new JList();
public CustomerFrame(Customer customer, Mall theMall){
MallCustomer mallObserver = new MallCustomer(this);
theMall.addObserver(mallObserver);
}
public setStoresListModel(ListModel listModel) {
storesList.setModel(listModel);
}
}
and
#Override
public void update(Observable o, Object arg) {
mallUpdate = (Mall) o;
DefaultListModel storeModel = new DefaultListModel();
//Stores update
for(int i = 0; i < mallUpdate.getStores().size();i++) {
storeModel.addElement(mallUpdate.getStores().get(i));
}
// storesList.setModel(storeModel);//a JList variable
thisFrame.setStoresListModel(storeModel);
}
Note: code not compiled nor tested
Edit
You've got several issues that I can see:
Your JList should not be public nor static. Make it a private instance field.
Again (as I suggested all along), give the Customer window a public setListModel type of method.
An application should only have one main JFrame, and so the CustomerFrame JFrame should not be a JFrame but rather should be a non-modal JDialog, or maybe better a JPanel that can be placed anywhere -- in its own JDialog, in the main JFrame.
Pass the main JFrame into your JDialogs so that the dialog can register the parent JFrame in its super's constructor.
Pass the CustomerDialog instance into your MallObserver instance, and then use it to set a field inside of MallObserver.
In the update method, create or update the model and call `setListModel on the customer dialog instance that MallObserver holds.
Create Mall instance before calling initComponents(). This way you can use the same Mall instance inside of your action listener methods.
A nit-pick: when creating and posting MCVE's, get rid of the messy and distracting NetBeans generated code. Instead only post simple code and simple GUI's that you've created yourself, similar to the changes that I've made below.
And you MCVE should all fit in a single file. The file can have several classes, but it should be easy for us to cut and paste into our IDE's and then run.
For example:
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class AdminFrame extends javax.swing.JFrame {
private Mall theMall = new Mall(); //!!
public AdminFrame() {
initComponents();
//!! theMall = new Mall();
}
private void initComponents() {
jTextField1 = new javax.swing.JTextField();
jLabel1 = new javax.swing.JLabel();
addStoreBtn = new javax.swing.JButton();
newCustBtn = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jTextField1.setText("jTextField1");
jLabel1.setText("jLabel1");
addStoreBtn.setText("Add Store");
addStoreBtn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
theMall.addNewStore(jTextField1.getText());
}
});
addStoreBtn.setMnemonic(KeyEvent.VK_S);
newCustBtn.setText("New Customer");
newCustBtn.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
// !! CustomerFrame newCust = new CustomerFrame();
CustomerDialog newCust = new CustomerDialog(AdminFrame.this, theMall);
newCust.pack();
newCust.setLocationByPlatform(true);
newCust.setVisible(true);
}
});
newCustBtn.setMnemonic(KeyEvent.VK_C);
JPanel mainPanel = new JPanel();
mainPanel.add(jLabel1);
mainPanel.add(jTextField1);
mainPanel.add(addStoreBtn);
mainPanel.add(newCustBtn);
add(mainPanel);
pack();
setLocationRelativeTo(null);
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new AdminFrame().setVisible(true);
}
});
}
private javax.swing.JButton addStoreBtn;
private javax.swing.JButton newCustBtn;
private javax.swing.JLabel jLabel1;
private javax.swing.JTextField jTextField1;
}
class MallObserver implements Observer {
private Mall mallUpdate;
private CustomerDialog customerDialog; // !!
// !!
public MallObserver(CustomerDialog customerFrame) {
this.customerDialog = customerFrame; // !!
}
#Override
public void update(Observable o, Object arg) {
mallUpdate = (Mall) o;
DefaultListModel<String> listModel = new DefaultListModel<>();
for (int i = 0; i < mallUpdate.getStores().size(); i++) {
listModel.addElement(mallUpdate.getStores().get(i));
}
customerDialog.setListModel(listModel);
}
}
#SuppressWarnings("serial")
class CustomerDialog extends JDialog { //!!
// !!!!!!! public CustomerFrame() {
// initComponents();
// }
public void setListModel(ListModel<String> listModel) {
jList1.setModel(listModel);
}
public CustomerDialog(AdminFrame adminFrame, Mall theMall) {
super(adminFrame, "Customer Dialog", ModalityType.MODELESS);
initComponents();
// !! MallObserver mallObs = new MallObserver();
MallObserver mallObs = new MallObserver(this); // !!
theMall.addObserver(mallObs);
}
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jList1 = new JList<>();
jList1.setPrototypeCellValue(" ");
jList1.setVisibleRowCount(15);
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
jList1.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
jScrollPane1.setViewportView(jList1);
add(jScrollPane1);
pack();
}
// public static javax.swing.JList jList1;
private JList<String> jList1;
private JScrollPane jScrollPane1;
}
class Mall extends Observable {
private ArrayList<String> stores;
public Mall() {
stores = new ArrayList<String>();
}
public void addNewStore(String store) {
stores.add(store);
setChanged();
notifyObservers(store);
}
public ArrayList<String> getStores() {
return stores;
}
}

JScrollPane and autoscroll: Disturbing scrolling behavior

I am writing an application which uses a JScrollPane. In this JScrollPane I want to automatically display search results, This means, that I have to dynamically add and remove the results within the JScrollPane. The results are realised as JTextArea, which are embeded within a GridBagLayout.
When there is a high number of search results, the JScrollPane automatically scrolls to the bottom (It should be at the top). I have solved it with a solution I found here. The problem hereby is, that you can see, how it scrolls back to the top. Is it possible to remove this behaviour?
The following things I found out:
I have to remove the previous search results to display the new ones. If I don't remove the previous ones, it displays correctly.
It neither solves the prblem wgeb I update the JScrollPane every tune after adding arow nor when updating only after adding all rows.
The best would be to just disable autoscroll. I have created an executable example to demonstrate this behavior. When clicking the button "Add Row", 500 rows are added. When clicking it several times, it becomes very clear.
Thank you very much for your help!
import java.awt.GridBagConstraints;
import javax.swing.JTextArea;
public class ScrollPaneTest extends javax.swing.JFrame {
private javax.swing.JButton jButton1;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JScrollPane jScrollPane1;
/**
* Creates new form ScrollPaneTest
*/
public ScrollPaneTest() {
initComponents();
}
/**
* Adds a new row.
* #param index The index of the new row.
*/
private void addRow(int index) {
JTextArea row = new JTextArea("Area " + index);
row.setEditable(false);
row.setBorder(null);
GridBagConstraints gridBagConstraints = new GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = index;
gridBagConstraints.fill = GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(2, 0, 2, 0);
jPanel2.add(row, gridBagConstraints);
}
/**
* Initializes the components.
*/
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jPanel1 = new javax.swing.JPanel();
jPanel2 = new javax.swing.JPanel();
jButton1 = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
jScrollPane1.setPreferredSize(new java.awt.Dimension(400, 400));
jScrollPane1.setViewportView(jPanel1);
jPanel1.setLayout(new java.awt.BorderLayout());
jPanel2.setLayout(new java.awt.GridBagLayout());
jPanel1.add(jPanel2, java.awt.BorderLayout.NORTH);
jScrollPane1.setViewportView(jPanel1);
jButton1.setText("Create Rows");
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)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addGap(148, 148, 148)
.addComponent(jButton1)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 245, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jButton1)
.addGap(0, 21, Short.MAX_VALUE))
);
pack();
}
/**
* Creates 500 new rows.
* #param evt
*/
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
jPanel2.removeAll();
for(int i = 0; i < 1000; i++) {
addRow(i);
}
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
jScrollPane1.getVerticalScrollBar().setValue(0);
}
});
jPanel2.validate();
jPanel2.repaint();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ScrollPaneTest().setVisible(true);
}
});
}
}
UPDATE 1
I removed the lambda expressions. Hopefully it should be now compileable also with < Java 8.
UPDATE 2
The problem with the disturbing scrolling behavior has been solved by replacing
jPanel2.validate();
jPanel2.repaint();
with
jScrollPane1.validate();
jScrollPane1.repaint();
Nevertheless, both answers to this question can be very helpful in some other cases and should be given attention.
One way to achieve this is to have a custom JViewPort for your scrollpane. This custom viewport overrides setViewPosition and uses a flag to prevent the scroll, or not.
Here is an example of such code, before changing the content of the textarea, we "lock" the viewport to prevent scrolling, and we unlock it later:
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class TestNoScrolling {
private int lineCount = 0;
private LockableViewPort viewport;
private JTextArea ta;
private final class LockableViewPort extends JViewport {
private boolean locked = false;
#Override
public void setViewPosition(Point p) {
if (locked) {
return;
}
super.setViewPosition(p);
}
public boolean isLocked() {
return locked;
}
public void setLocked(boolean locked) {
this.locked = locked;
}
}
protected void initUI() {
JFrame frame = new JFrame("test");
ta = new JTextArea(5, 30);
JScrollPane scrollpane = new JScrollPane();
viewport = new LockableViewPort();
viewport.setView(ta);
scrollpane.setViewport(viewport);
frame.add(scrollpane);
frame.pack();
frame.setVisible(true);
Timer t = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
viewport.setLocked(true);
ta.append("Some new line " + lineCount++ + "\n");
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
viewport.setLocked(false);
}
});
}
});
t.setRepeats(true);
t.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestNoScrolling().initUI();
}
});
}
}
You could simply set the Caret position to the start position (0), for example...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class ScrollNoMore {
public static void main(String[] args) {
new ScrollNoMore ();
}
public ScrollNoMore () {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea ta;
private JScrollPane sp;
private Random rnd = new Random();
private boolean initalised = false;
public TestPane() {
setLayout(new BorderLayout());
ta = new JTextArea(20, 40);
sp = new JScrollPane(ta);
add(sp);
Timer timer = new Timer(250, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
long value = rnd.nextLong();
ta.append(String.valueOf(value) + "\n");
if (!initalised) {
ta.setCaretPosition(0);
initalised = true;
}
}
});
timer.start();
}
}
}
This will only set it the first time the Timer runs, this means that if you move the Caret or scroll position for some reason, it won't "flick" back. You could set up a series of states where by if the user moved the current view, it didn't effect the scrolling, but could be reset as required.

Progress Monitor Implementation in Java

I want to show the progress of my program process which using progress monitor in java. i've put this code below as progress monitor in my new frame.
package eksim.view;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.ProgressMonitor;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
public class ProgBar extends javax.swing.JInternalFrame implements ActionListener {
static ProgressMonitor pbar;
static int counter = 0;
/**
* Creates new form ProgBar
*/
public ProgBar() {
initComponents();
}
public void ProgressMonitorExample() {
super("Progress Monitor Demo");
setSize(250, 100);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pbar = new ProgressMonitor(null, "Monitoring Progress",
"Initializing . . .", 0, 100);
// Fire a timer every once in a while to update the progress.
Timer timer = new Timer(500, this);
timer.start();
setVisible(true);
}
public static void main(String args[]) {
UIManager.put("ProgressMonitor.progressText", "This is progress?");
UIManager.put("OptionPane.cancelButtonText", "Go Away");
ProgressMonitorExample();
}
public void actionPerformed(ActionEvent e) {
// Invoked by the timer every half second. Simply place
// the progress monitor update on the event queue.
SwingUtilities.invokeLater(new Update());
}
class Update implements Runnable {
public void run() {
if (pbar.isCanceled()) {
pbar.close();
System.exit(1);
}
pbar.setProgress(counter);
pbar.setNote("Operation is " + counter + "% complete");
counter += 2;
}
}
/**
* 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() {
jProgressBar1 = new javax.swing.JProgressBar();
setClosable(true);
setIconifiable(true);
setMaximizable(true);
setTitle("Progress Monitor");
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(31, 31, 31)
.addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 335, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(28, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap(66, Short.MAX_VALUE)
.addComponent(jProgressBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(48, 48, 48))
);
pack();
}// </editor-fold>
// Variables declaration - do not modify
private javax.swing.JProgressBar jProgressBar1;
// End of variables declaration
}
But, it didn't show anything as it works. Could anyone help me? Thanks
Apart from a few compilation problems in your code (detailed below), it works fine here. The progress bar updates as expected here.
First, move the code from public void ProgressMonitorExample() to the constructor, and remove that method. The constructor should look like this:
public ProgBar() {
super("Progress Monitor Demo");
initComponents();
setSize(250, 100);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pbar = new ProgressMonitor(null, "Monitoring Progress",
"Initializing . . .", 0, 100);
// Fire a timer every once in a while to update the progress.
Timer timer = new Timer(500, this);
timer.start();
setVisible(true);
}
Second, since public void ProgressMonitorExample() is now gone, properly create a new ProgBar object instead:
public static void main(String args[]) {
UIManager.put("ProgressMonitor.progressText", "This is progress?");
UIManager.put("OptionPane.cancelButtonText", "Go Away");
ProgBar pb = new ProgBar();
}

Dynamically add menuitem in menu without closing the menu

I want to add JMenuItem without closing JMenu. A menu contains a JTextField, When I press enter in text field, it added a menu Item. My problem is the size of added menu item is too small.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JMenuItem;
import javax.swing.JTextField;
public class NewJFrame extends javax.swing.JFrame {
public NewJFrame() {
initComponents();
this.jMenu1.addSeparator();
final JTextField jTextField = new JTextField("Menu 1",20);
this.jMenu1.add(jTextField);
jTextField.addActionListener(new ActionListener( ){
#Override
public void actionPerformed(ActionEvent e) {
final JMenuItem jMenuItem = new JMenuItem(jTextField.getText());
jMenu1.add(jMenuItem);
jMenuItem.repaint();
jMenuItem.revalidate();
}
});
}
#SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jMenuBar1 = new javax.swing.JMenuBar();
jMenu1 = new javax.swing.JMenu();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jMenu1.setText("File");
jMenuBar1.add(jMenu1);
setJMenuBar(jMenuBar1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 400, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 279, Short.MAX_VALUE)
);
pack();
}// </editor-fold>//GEN-END:initComponents
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JMenu jMenu1;
private javax.swing.JMenuBar jMenuBar1;
// End of variables declaration//GEN-END:variables
}
When I am pressing enter, menu add a menu item, but its width is too small.
How can I fix it?
You have to update the popupMenu of the jMenu1, calling:
jMenu1.getPopupMenu().pack();
instead of
jMenuItem.repaint();
jMenuItem.revalidate();
Instead of repainting it, close the menu and reopen it. Just tried it and it works great, it's as quick as repainting on the spot.
jMenu1.add(jMenuItem);
//jMenuItem.repaint();
//jMenuItem.revalidate();
MenuElement[] selectionPath = MenuSelectionManager.defaultManager().getSelectedPath();
MenuSelectionManager.defaultManager().clearSelectedPath();
MenuSelectionManager.defaultManager().setSelectedPath(selectionPath);

Make a textfield visible on itemStatechanged event of a checkbox

How to make a text field visible on itemStatechanged event of a check box in Swing?
I am trying to create a frame with a check box and a text field. I want the text field to be displayed only when the check box is selected. So when I initialize the components, I have set the textfield.setvisible to false and for the check box added a addItemListener and call the itemStateChanged event and there is the check box is selected, I set the setVisible method to true.
My SSCCE looks like:
package ui;
public class Evaluator extends javax.swing.JFrame {
public Evaluator() {
initComponents();
}
private void initComponents() {
jCheckBox1 = new javax.swing.JCheckBox();
jTextField1 = new javax.swing.JTextField();
jTextField1.setVisible(false);
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setPreferredSize(new java.awt.Dimension(800, 800));
jCheckBox1.setFont(new java.awt.Font("Tahoma", 0, 14));
jCheckBox1.setText("Properties");
jCheckBox1.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
jCheckBox1ItemStateChanged(evt);
}
});
jTextField1.setFont(new java.awt.Font("Tahoma", 0, 14));
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(jCheckBox1)
.addGap(41, 41, 41)
.addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(155, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap(229, Short.MAX_VALUE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jCheckBox1)
.addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 37, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(34, 34, 34))
);
pack();
}
private void jCheckBox1ItemStateChanged(java.awt.event.ItemEvent evt) {
// TODO add your handling code here:
if(evt.getStateChange()== java.awt.event.ItemEvent.SELECTED){
jTextField1.setVisible(true);
}
}
public static void main(String args[]) {
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(Evaluator.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(Evaluator.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(Evaluator.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(Evaluator.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Evaluator().setVisible(true);
}
});
}
private javax.swing.JCheckBox jCheckBox1;
private javax.swing.JTextField jTextField1;
}
Basically, you need to invalidate the frame (or parent container) to force it be re-layout
private void jCheckBox2ItemStateChanged(java.awt.event.ItemEvent evt) {
jTextField1.setVisible(jCheckBox2.isSelected());
invalidate();
validate();
}
Updated
I'd also suggest that you avoid adding your entire UI onto a top level container, instead use a JPanel as you base component and build you UI's around them. When you're ready, simply add the base panel to what ever top level container you need.
For many components in one space, use a CardLayout as see in this short example.
Here is a more specific example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class CardLayoutDemo {
public static void main(String[] args) {
Runnable r = new Runnable () {
public void run() {
final JCheckBox show = new JCheckBox("Have Text", false);
JPanel ui = new JPanel(new
FlowLayout(FlowLayout.CENTER, 5, 5));
ui.add( show );
final CardLayout cl = new CardLayout();
final JPanel cards = new JPanel(cl);
ui.add(cards);
cards.add(new JPanel(), "notext");
cards.add(new JTextField(8), "text");
ItemListener al = new ItemListener(){
public void itemStateChanged(ItemEvent ie) {
if (show.isSelected()) {
cl.show(cards, "text");
} else {
cl.show(cards, "notext");
}
}
};
show.addItemListener(al);
JOptionPane.showMessageDialog(null, ui);
}
};
SwingUtilities.invokeLater(r);
}
}
great lesson, how the LayoutManager works, only GridLayout can do that without any issue, but this is its property
last JComponent in the row or column (part of then is about) can't be invisible, then container is shrinked
easiest work_around is to display container, then to call setVisible(false) wrapped into invokeLater
... ....
import java.awt.event.ItemEvent;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Evaluator {
private JFrame frame = new JFrame();
private JPanel panel = new JPanel();
private JCheckBox checkBox = new JCheckBox();
private JTextField textField = new JTextField(10);
public Evaluator() {
checkBox.setText("Properties");
checkBox.addItemListener(new java.awt.event.ItemListener() {
#Override
public void itemStateChanged(java.awt.event.ItemEvent evt) {
if (evt.getStateChange() == ItemEvent.SELECTED) {
textField.setVisible(true);
} else {
textField.setVisible(false);
}
}
});
//panel.setLayout(new GridLayout());
//panel.setLayout(new SpringLayout());
//panel.setLayout(new BorderLayout());
//panel.setLayout(new GridBagLayout());
//panel.setLayout(new BoxLayout(panel, BoxLayout.LINE_AXIS));
panel.add(checkBox/*, BorderLayout.NORTH*/);
panel.add(textField/*, BorderLayout.SOUTH*/);
//panel.doLayout();
//textField.setVisible(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setVisible(true);
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
textField.setVisible(false);
}
});
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Evaluator evaluator = new Evaluator();
}
});
}
}

Categories

Resources