Hello Guru's I am a beginner Java swing developer and am trying to build a simple app... here is a simplified version.
Setup: 1 JFrame, 2 BorderLayout based tabbed panels (A and B) each has 1 textfiled, shared JPanel class with combo box and ItemListener initialized in each tab's (North)
Issue: How to control updates to textfield's text based on which panel it came from eg. if I select Apples in TabA, the Item Listener updates the TextField on TabB as well. What I would like to accomplish is determine where the call came from TabA or TabB and only update the textfield associated with that tab.
Hope this makes some sense
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel contentPane;
public JTextField tfPanelA;
public JTextField tfPanelB;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Main frame = new Main();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Main() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
contentPane.add(tabbedPane, BorderLayout.CENTER);
JPanel panelA = new JPanel();
tabbedPane.addTab("Tab A", null, panelA, null);
panelA.setLayout(new BorderLayout(0, 0));
sharedPanel s1 = new sharedPanel(this);
panelA.add(s1, BorderLayout.NORTH);
tfPanelA = new JTextField();
panelA.add(tfPanelA);
tfPanelA.setColumns(10);
JPanel panelB = new JPanel();
tabbedPane.addTab("Tab B", null, panelB, null);
panelB.setLayout(new BorderLayout(0, 0));
sharedPanel s2 = new sharedPanel(this);
panelB.add(s2, BorderLayout.NORTH);
tfPanelB = new JTextField();
panelB.add(tfPanelB);
tfPanelB.setColumns(10);
}
}
// Shared Class...
public class sharedPanel extends JPanel {
private Main app;
private String[] clist = {"Apples","Oranges","Bananas"};
/**
* Create the panel.
*/
public sharedPanel(final Main app) {
this.app=app;
setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
JComboBox<String> comboBox = new JComboBox<String>();
comboBox.setModel(new DefaultComboBoxModel<String>(clist));
comboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
//update PanelA's textfield ONLY if called from PanelA
// do this if called from PanelA
app.tfPanelA.setText(e.getItem().toString());
// do this if called from PanelB
app.tfPanelB.setText(e.getItem().toString());
}
});
add(comboBox);
}
}
Since you have create a new instance of sharedPanel for each tab, simply provide a reference to the text field you want to be updated to it...
Which you end up with something more like...
public class sharedPanel extends JPanel {
private JTextField field;
private String[] clist = {"Apples","Oranges","Bananas"};
public sharedPanel(final JTextField field) {
this.field=field;
setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
JComboBox<String> comboBox = new JComboBox<String>();
comboBox.setModel(new DefaultComboBoxModel<String>(clist));
comboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
sharedPanel.this.field.setText(e.getItem().toString());
}
});
add(comboBox);
}
}
Updated with a "model" example
This is very basic example of just one possible use of a model to bridge the changes between the common panel and other panels. This means that the common panel doesn't care about anything else and updates the supplied model, which fires events to interested parties who can take appropriate action as required.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TabbedModel {
protected static final String[] MAIN_LIST = {"Apples","Oranges","Bananas"};
public static void main(String[] args) {
new TabbedModel();
}
public TabbedModel() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JTabbedPane tabPane = new JTabbedPane();
tabPane.addTab("A", new ATab());
tabPane.addTab("B", new ATab());
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(tabPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DefaultCommonModel implements CommonModel {
private List<ChangeListener> listeners;
private String value;
public DefaultCommonModel() {
listeners = new ArrayList<>(25);
}
#Override
public void addChangeListener(ChangeListener listener) {
listeners.add(listener);
}
#Override
public void removeChangeListener(ChangeListener listener) {
listeners.remove(listener);
}
#Override
public void setValue(String aValue) {
if (aValue == null ? value != null : !aValue.equals(value)) {
value = aValue;
fireStateChanged();
}
}
#Override
public String getValue() {
return value;
}
protected void fireStateChanged() {
if (!listeners.isEmpty()) {
ChangeEvent evt = new ChangeEvent(this);
for (ChangeListener listener : listeners) {
listener.stateChanged(evt);
}
}
}
}
public interface CommonModel {
public void addChangeListener(ChangeListener listener);
public void removeChangeListener(ChangeListener listener);
public void setValue(String value);
public String getValue();
}
public class CommonPanel extends JPanel {
private CommonModel model;
private JComboBox comboBox;
public CommonPanel(CommonModel model) {
this.model = model;
setLayout(new GridBagLayout());
comboBox = new JComboBox(new DefaultComboBoxModel<>(MAIN_LIST));
comboBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
String value = (String) e.getItem();
CommonPanel.this.model.setValue(value);
}
});
add(comboBox);
}
}
public class ATab extends JPanel {
private List<JTextField> fields;
public ATab() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
DefaultCommonModel model = new DefaultCommonModel();
model.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
CommonModel model = (CommonModel) e.getSource();
for (JTextField field : fields) {
field.setText(model.getValue());
}
}
});
CommonPanel commonPanel = new CommonPanel(model);
add(commonPanel, gbc);
fields = new ArrayList<>(25);
for (int index = 0; index < random(); index++) {
JTextField field = new JTextField(10);
add(field, gbc);
fields.add(field);
}
}
protected int random() {
return (int)Math.round(Math.random() * 9) + 1;
}
}
}
Since you have two instances of your SharedPanel you can add the textfield to be updated as a reference to the constructor:
SharedPanel s1 = new SharedPanel(this, tfPanelA);
and
public SharedPanel(final Main app, final JTextField tf) {
...
comboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
tf.setText(e.getItem().toString());
}
});
...
}
Related
I am new to Java Swing and I am trying to learn how to close one frame without closing the other one using button. For example I have a frame1/window that just have a button called login. Once I click on login button, another window appear frame2. On frame2 I just have a sample JLabel "Hello And Welcome", button called Logout. I want to be able to click on the Logout button on frame2 and frame2 window should close, but frame1 window show still be open. I have try setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE), but it only work if I click on the x icon on the top right of the frame2 window. Does anyone know of a way to close a frame when you click on a button?
public class Frame1 extends JFrame implements ActionListener{
private static JButton login = new JButton("Login");
private static JFrame f = new JFrame("Login");
Frame1(){
f.setSize(1000,750);
f.setLocation(750, 250);
login.setBounds(250, 350, 150, 30);
f.add(login);
f.setLayout(null);
f.setVisible(true);
login.addActionListener(this);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e){
if (e.getSource() == login){
Frame2.frame2windown();
}
}
public static void main(String [] args){
Frame1 login1 = new Frame1();
}
}
public class Frame2 extends JFrame implements ActionListener{
private static JButton logout = new JButton("Logout");
private static JLabel jb1 = new JLabel ("Hello And Welcome");
private static JFrame f = new JFrame("Log Out");
Frame2(){
f.setSize(1000,750);
f.setLocation(750, 250);
jb1.setBounds(250, 150, 350, 30);
logout.setBounds(250, 350, 150, 30);
f.add(logout);
f.add(jb1);
f.setLayout(null);
f.setVisible(true);
logout.addActionListener(this);
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
public void actionPerformed(ActionEvent a){
if(a.getSource() == logout){
dispose();
WindowEvent closeWindow = new WindowEvent(this, JFrame.DISPOSE_ON_CLOSE);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(closeWindow);
}
}
public static void frame2windown(){
Frame2 f2 = new Frame2();
}
}
So, there are a whole bunch of concepts your need to try and learn.
It's generally recommended NOT to extend from top level containers (like JFrame). You're not adding any new functionality too them; they are complicated, compound components; you lock yourself into a single use case (what happens if you want to include the UI in another UI or use a dialog instead of frame?!)
Multiple frames aren't always a good idea and can be confusing to the user. Generally, with login workflows though, I might argue a login dialog is generally a better solution, but you need to understand the use cases to make those determinations.
Swing is a large, rich and diverse API, it has a LOT of inbuilt functionality, which you can use, to make your life easier (although it doesn't always seem this way)
Layout managers are an absolutely required feature and you really need to take the time to learn them, see Laying Out Components Within a Container for more details.
So, a really quick example of using a CardLayout and a basic "observer pattern", which decouples and separates responsibility.
import java.awt.CardLayout;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.EventListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new NavigationPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class NavigationPane extends JPanel {
protected enum NavigationTarget {
LOGIN, MAIN;
}
private LoginPane loginPane;
private MainPane mainPane;
private CardLayout cardLayout;
public NavigationPane() {
cardLayout = new CardLayout();
setLayout(cardLayout);
loginPane = new LoginPane();
loginPane.addLoginListener(new LoginPane.LoginListener() {
#Override
public void loginDidFail(LoginPane source) {
JOptionPane.showMessageDialog(NavigationPane.this, "You are not unauthroised", "Error", JOptionPane.ERROR_MESSAGE);
}
#Override
public void loginWasSuccessful(LoginPane source) {
navigateTo(NavigationTarget.MAIN);
}
});
mainPane = new MainPane();
add(loginPane, NavigationTarget.LOGIN.name());
add(mainPane, NavigationTarget.MAIN.name());
navigateTo(NavigationTarget.LOGIN);
}
protected void navigateTo(NavigationTarget target) {
cardLayout.show(this, target.name());
}
}
public static class LoginPane extends JPanel {
public static interface LoginListener extends EventListener {
public void loginDidFail(LoginPane source);
public void loginWasSuccessful(LoginPane source);
}
public LoginPane() {
setBorder(new EmptyBorder(10, 10, 10, 10));
setLayout(new GridBagLayout());
JButton btn = new JButton("Login");
btn.addActionListener(new ActionListener() {
private Random rnd = new Random();
#Override
public void actionPerformed(ActionEvent e) {
// Do some logic here
if (rnd.nextBoolean()) {
fireLoginWasSuccessful();
} else {
fireLoginDidFail();
}
}
});
add(btn);
}
public void addLoginListener(LoginListener listener) {
listenerList.add(LoginListener.class, listener);
}
public void removeLoginListener(LoginListener listener) {
listenerList.remove(LoginListener.class, listener);
}
protected void fireLoginDidFail() {
LoginListener[] listeners = listenerList.getListeners(LoginListener.class);
for (LoginListener listener : listeners) {
listener.loginDidFail(this);
}
}
protected void fireLoginWasSuccessful() {
LoginListener[] listeners = listenerList.getListeners(LoginListener.class);
for (LoginListener listener : listeners) {
listener.loginWasSuccessful(this);
}
}
}
public static class MainPane extends JPanel {
public MainPane() {
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(10, 10, 10, 10));
add(new JLabel("Welcome"));
}
}
}
JDialog based login workflow
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
NavigationPane navigationPane = new NavigationPane();
JFrame frame = new JFrame();
frame.add(navigationPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
if (LoginPane.showLoginDialog(navigationPane)) {
navigationPane.didLogin();
} else {
frame.dispose();
}
}
});
}
public static class NavigationPane extends JPanel {
protected enum NavigationTarget {
SPLASH, MAIN;
}
private SplashPane splashPane;
private MainPane mainPane;
private CardLayout cardLayout;
public NavigationPane() {
cardLayout = new CardLayout();
setLayout(cardLayout);
mainPane = new MainPane();
splashPane = new SplashPane();
add(splashPane, NavigationTarget.SPLASH.name());
add(mainPane, NavigationTarget.MAIN.name());
navigateTo(NavigationTarget.SPLASH);
}
protected void navigateTo(NavigationTarget target) {
cardLayout.show(this, target.name());
}
public void didLogin() {
navigateTo(NavigationTarget.MAIN);
}
}
public static class LoginPane extends JPanel {
private Random rnd = new Random();
private boolean isAuthorised = false;
public LoginPane() {
setBorder(new EmptyBorder(10, 10, 10, 10));
setLayout(new GridBagLayout());
add(new JLabel("User name and password fields go here"));
}
protected void authenticate() {
// Authenticate
isAuthorised = rnd.nextBoolean();
if (!isAuthorised) {
JOptionPane.showMessageDialog(this, "You are not authorised", "Error", JOptionPane.ERROR_MESSAGE);
}
}
// So this should return some kind of "session" or something so
// can identify the user, but for now, we'll just use
// a boolean
public boolean isAuthorised() {
return isAuthorised;
}
public static boolean showLoginDialog(Component parent) {
LoginPane loginPane = new LoginPane();
JPanel panel = new JPanel(new BorderLayout());
JPanel buttonPane = new JPanel(new GridBagLayout());
JButton okayButton = new JButton("Login");
JButton cancelButton = new JButton("Cancel");
buttonPane.add(okayButton);
buttonPane.add(cancelButton);
panel.add(loginPane);
panel.add(buttonPane, BorderLayout.SOUTH);
JDialog dialog = new JDialog(SwingUtilities.windowForComponent(parent));
dialog.add(panel);
okayButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
loginPane.authenticate();
if (loginPane.isAuthorised()) {
dialog.dispose();
}
}
});
cancelButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
dialog.dispose();
}
});
dialog.setModal(true);
dialog.pack();
dialog.setLocationRelativeTo(parent);
dialog.setVisible(true);
return loginPane.isAuthorised();
}
}
public static class SplashPane extends JPanel {
public SplashPane() {
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(10, 10, 10, 10));
add(new JLabel("This is a splash panel, put some nice graphics here"));
}
}
public static class MainPane extends JPanel {
public MainPane() {
setLayout(new GridBagLayout());
setBorder(new EmptyBorder(10, 10, 10, 10));
add(new JLabel("Welcome"));
}
}
}
You duplicated the JFrame, created a JFrame field f inside the JFrame.
Do not use static components like the button.
public class Frame1 extends JFrame implements ActionListener {
private final JButton login = new JButton("Login");
Frame1() {
setTitle("Login");
setSize(1000, 750);
setLocation(750, 250);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
login.setBounds(250, 350, 150, 30);
add(login);
login.addActionListener(this);
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == login) {
Frame2.frame2windown();
}
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
Frame1 login1 = new Frame1();
}
}
}
Use the swing/awt event queue (invokeLater) as on this thread window events are handled and dispatched further.
And Frame2:
public class Frame2 extends JFrame implements ActionListener {
private JButton logout = new JButton("Logout");
private JLabel jb1 = new JLabel("Hello And Welcome");
Frame2() {
setTitle("Logout");
setSize(1000, 750);
setLocation(750, 250);
setLayout(null);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
jb1.setBounds(250, 150, 350, 30);
logout.setBounds(250, 350, 150, 30);
add(logout);
add(jb1);
logout.addActionListener(this);
setVisible(true);
}
public void actionPerformed(ActionEvent a) {
if (a.getSource() == logout) {
setVisible(false); // <--- ALL
}
}
public static void frame2windown() {
Frame2 f2 = new Frame2();
}
}
JFrame.setVisible does it all. Especially setVisible(true) should maybe even done after the constructor is called, so it always is last.
Another remark, dive into layout managers fast. Absolute layouts (null) are a PITA.
I wanted to display same textfield and label in both the panels that are added to JTabbedPane but one of panel is displaying the textfield and label and the other is not, when added the same textfield and label for both the panels.
You can only display a component in one container. Better to have your JPanels share the same model, which for the JTextField is its Document, and for the JLabel -- well its text (not really a model that you can extract, so you'll have to change both yourself).
A bit overconvoluted example:
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.EventListenerList;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.PlainDocument;
#SuppressWarnings("serial")
public class SharedModels extends JPanel {
private static final int TABS = 10;
private JTabbedPane tabbedPane = new JTabbedPane();
private JTextField labelText = new JTextField(10);
private MyModel myModel = new MyModel();
public SharedModels() {
for (int i = 0; i < TABS; i++) {
MyPanel myPanel = new MyPanel(myModel);
String text = "tab: " + (i + 1);
tabbedPane.addTab(text, myPanel);
}
JPanel topPanel = new JPanel();
topPanel.add(new JLabel("Text for JLabel:"));
topPanel.add(labelText);
labelText.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void removeUpdate(DocumentEvent e) {
setLabelText(e);
}
#Override
public void insertUpdate(DocumentEvent e) {
setLabelText(e);
}
#Override
public void changedUpdate(DocumentEvent e) {
setLabelText(e);
}
private void setLabelText(DocumentEvent e) {
Document doc = e.getDocument();
int length = doc.getLength();
try {
String text = doc.getText(0, length);
myModel.setLabelText(text);
} catch (BadLocationException e1) {
e1.printStackTrace();
}
}
});
setLayout(new BorderLayout());
add(topPanel, BorderLayout.PAGE_START);
add(tabbedPane, BorderLayout.CENTER);
add(new MyPanel(myModel), BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
SharedModels mainPanel = new SharedModels();
JFrame frame = new JFrame("SharedModels");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class MyModel {
private Document document = new PlainDocument();
private String labelText = "";
private EventListenerList eventListenerList = new EventListenerList();
private ChangeEvent changeEvent = null;
public void addChangeListener(ChangeListener l) {
eventListenerList.add(ChangeListener.class, l);
}
public void removeChangeListener(ChangeListener l) {
eventListenerList.remove(ChangeListener.class, l);
}
public String getLabelText() {
return labelText;
}
public void setLabelText(String labelText) {
this.labelText = labelText;
fireChangeListeners();
}
protected void fireChangeListeners() {
Object[] listeners = eventListenerList.getListenerList();
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i] == ChangeListener.class) {
if (changeEvent == null) {
changeEvent = new ChangeEvent(this);
}
((ChangeListener) listeners[i + 1]).stateChanged(changeEvent);
}
}
}
public Document getDocument() {
return document;
}
}
#SuppressWarnings("serial")
class MyPanel extends JPanel {
private JLabel label = new JLabel("");
private JTextField textField = new JTextField(10);
public MyPanel(MyModel myModel) {
textField.setDocument(myModel.getDocument());
myModel.addChangeListener(ce -> {
label.setText(myModel.getLabelText());
});
add(new JLabel("Label text:"));
add(label);
add(textField);
setPreferredSize(new Dimension(400, 100));
}
}
I want to display a list of strings in a window and i tried to use a JPanel surounded by JScrollPane because the size of the strings list is unknown. The problem is that the window is displaying the text Horizontally and i want to be displayed line after line. How to fix this? This is the code i've written so far.
package interface_classes;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JTextArea;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
public class ErrorMessageW {
private JFrame errorMessageW;
private ArrayList<String> errors;
private JPanel panel;
private JScrollPane scrollPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
final ArrayList<String> err = new ArrayList<>();
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ErrorMessageW window = new ErrorMessageW(err);
window.errorMessageW.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public ErrorMessageW(ArrayList<String> err) {
errors = err;
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
errorMessageW = new JFrame();
errorMessageW.setTitle("Unfilled forms");
errorMessageW.setBounds(100, 100, 367, 300);
errorMessageW.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton btnOk = new JButton("OK");
btnOk.setBounds(239, 208, 89, 23);
btnOk.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
errorMessageW.dispose();
}
});
errorMessageW.getContentPane().setLayout(null);
errorMessageW.getContentPane().add(btnOk);
scrollPane = new JScrollPane();
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setBounds(10, 10, 330, 175);
errorMessageW.getContentPane().add(scrollPane);
panel = new JPanel();
for(String s : errors){
JTextArea text = new JTextArea(1,20);
text.setText(s);
text.setFont(new Font("Verdana",1,10));
text.setForeground(Color.RED);
panel.add(text);
}
scrollPane.setViewportView(panel);
}
public JFrame getErrorMessageW() {
return errorMessageW;
}
public void setErrorMessageW(JFrame errorMessageW) {
this.errorMessageW = errorMessageW;
}
}
This is what i get
This is what i want, but using the JScrollPane:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.util.ArrayList;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class ErrorMessageW {
private JFrame errorMessageW;
private ArrayList<String> errors;
private JPanel panel;
private JScrollPane scrollPane;
private JTextArea errorMessage = new JTextArea(3, 30);
/**
* Launch the application.
*/
public static void main(String[] args) {
final ArrayList<String> err = new ArrayList<String>();
err.add("Short String");
err.add("A very very very very very very very very very very very "
+ "very very very very very very very very very very very "
+ "very very very very very very very very long String");
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ErrorMessageW window = new ErrorMessageW(err);
window.errorMessageW.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public ErrorMessageW(ArrayList<String> err) {
errors = err;
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
errorMessageW = new JFrame();
JPanel contentPane = new JPanel(new BorderLayout(5, 15));
contentPane.setBorder(new EmptyBorder(10, 10, 10, 10));
errorMessage.setLineWrap(true);
errorMessage.setWrapStyleWord(true);
JScrollPane jsp = new JScrollPane(
errorMessage,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
);
contentPane.add(jsp, BorderLayout.PAGE_START);
errorMessageW.add(contentPane);
errorMessageW.setTitle("Unfilled forms");
errorMessageW.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JButton btnOk = new JButton("OK");
btnOk.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
errorMessageW.dispose();
}
});
JPanel btnConstrain = new JPanel(new FlowLayout(FlowLayout.TRAILING));
btnConstrain.add(btnOk);
contentPane.add(btnConstrain, BorderLayout.PAGE_END);
scrollPane = new JScrollPane();
scrollPane.setVerticalScrollBarPolicy(
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setHorizontalScrollBarPolicy(
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
contentPane.add(scrollPane, BorderLayout.CENTER);
DefaultListModel<String> listModel = new DefaultListModel<String>();
for (String s : errors) {
listModel.addElement(s);
}
final JList<String> errorList = new JList<String>(listModel);
Dimension preferredSize = new Dimension(errorMessage.getPreferredSize().width,200);
errorList.setPreferredSize(preferredSize);
ListSelectionListener errorSelect = new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
errorMessage.setText(errorList.getSelectedValue());
}
};
errorList.addListSelectionListener(errorSelect);
scrollPane.setViewportView(errorList);
errorMessageW.pack();
}
public JFrame getErrorMessageW() {
return errorMessageW;
}
public void setErrorMessageW(JFrame errorMessageW) {
this.errorMessageW = errorMessageW;
}
}
First of all, you could try, instead of creating multiple instances of JTextArea, using only one and appending each error to it like this:
JTextArea text = new JTextArea(1, 20);
text.setFont(new Font("Verdana",1,10));
text.setForeground(Color.RED);
for(String s : errors) {
text.append(s + "\n");
}
panel.add(text);
However, if you do need to create more than one JTextArea, you can use a BoxLayout like this:
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
You just need to write a function that adds a new line character as an element of your ArrayList after every other element in your ArrayList of errors. Below i did a test program that shows how that can be done. I also checked the oputput. Just paste the code and understand the working of code. All the best!
import java.util.ArrayList;
public class TestingArraylist {
static ArrayList<String> errors = new ArrayList<String>();
static final String[] warnings = new String[]{"Error 0 occured","Error 1 occured","Error 2 occured","Error 3 occured","Error 4 occured"};;
public static void addNewLineToArrayList(String[] elementofarraylist){
for(int i =0;i<elementofarraylist.length;i++){
errors.add(elementofarraylist[i]);
errors.add("\n"); //this is what you need to do!
}
}
public static void main(String[] args) {
addNewLineToArrayList(warnings);
//checking below if our work has really succeded or not!!
for(int j =0;j<errors.size();j++){
System.out.print(errors.get(j));
}
}
}
I would like to implement the cut method in java to provide the cut and paste functionality.I have already used StringSelection and getSystemClipboard() to provide the cut functionality(code below),but I wanna know how I can use java's inbuilt cut() method for it.
Code for cut functionality.
String t = qu.getText();
StringSelection s = new StringSelection(t);
this.getToolkit().getSystemClipboard().setContents(s, s);
qu.setText("");
I expected something like this to work but it didn't
qu.cut();
Thanks in advance.
If Swing just use the Actions available from the DefaultEditorKit:
new DefaultEditorKit.CutAction()
For example, a small program that uses default actions in a menu, a component-specific pop-up menu, and in buttons:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.text.*;
public class TestActions {
private String[] texts = {
"Hello", "Goodbye", "What the f***?", "Heck if I know", "Peace out man!"
};
private JTextArea textArea = new JTextArea(10, 30);
private Action[] textActions = { new DefaultEditorKit.CutAction(),
new DefaultEditorKit.CopyAction(), new DefaultEditorKit.PasteAction(), };
private JPanel mainPanel = new JPanel();
private JMenuBar menubar = new JMenuBar();
private JPopupMenu popup = new JPopupMenu();
private PopupListener popupListener = new PopupListener();
public TestActions() {
JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 5));
JMenu menu = new JMenu("Edit");
for (Action textAction : textActions) {
btnPanel.add(new JButton(textAction));
menu.add(new JMenuItem(textAction));
popup.add(new JMenuItem(textAction));
}
menubar.add(menu);
JPanel textFieldPanel = new JPanel(new GridLayout(0, 1, 5, 5));
for (String text: texts) {
JTextField textField = new JTextField(text, 15);
textField.addMouseListener(popupListener);
textFieldPanel.add(textField);
textField.addFocusListener(new FocusAdapter() {
#Override
public void focusGained(FocusEvent e) {
((JTextComponent)e.getSource()).selectAll();
}
});
}
textArea.addMouseListener(popupListener);
JScrollPane scrollPane = new JScrollPane(textArea);
JPanel textFieldPanelWrapper = new JPanel(new BorderLayout());
textFieldPanelWrapper.add(textFieldPanel, BorderLayout.NORTH);
mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
mainPanel.setLayout(new BorderLayout(5, 5));
mainPanel.add(btnPanel, BorderLayout.NORTH);
mainPanel.add(scrollPane, BorderLayout.CENTER);
mainPanel.add(textFieldPanelWrapper, BorderLayout.EAST);
}
public JComponent getMainPanel() {
return mainPanel;
}
private JMenuBar getMenuBar() {
return menubar;
}
private class PopupListener extends MouseAdapter {
public void mousePressed(MouseEvent e) {
maybeShowPopup(e);
}
public void mouseReleased(MouseEvent e) {
maybeShowPopup(e);
}
private void maybeShowPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
popup.show(e.getComponent(),
e.getX(), e.getY());
}
}
}
private static void createAndShowGui() {
TestActions testActions = new TestActions();
JFrame frame = new JFrame("Test Actions");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(testActions.getMainPanel());
frame.setJMenuBar(testActions.getMenuBar());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
It is because cut() method requires a selection in the text field. Try the following code:
qu.selectAll();
qu.cut();
I'm working on a downloader which looks like this at the moment:
The JFrame uses a BorderLayout.
In the NORTH, I have a JPanel(FlowLayout). In the SOUTH there is also a JPanel(FlowLayout), in the WEST I just have a JTextArea (in a JScrollPane). This is all shown correctly. However, in the EAST I currently have a JPanel(GridLayout(10, 1)).
I want to show up to 10 JProgressBars in the EAST section which are added and removed from the panel dynamically. The problem is, I can not get them to look like I want to them to look: I want the JProgressBars' width to fill up the entire EAST section because 1) This gives the app a more symmetrical look and 2) The ProgressBars may contain long strings that don't fit at the moment. I've tried putting the JPanel that contains the GridLayout(10, 1) in a flowlayout and then put that flowlayout in the EAST section, but that didn't work either.
My code (SSCCE) is currently as follows:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
new DownloadFrame();
}
private static class DownloadFrame extends JFrame {
private JButton downloadButton;
private JTextField threadIdTextField;
private JTextArea downloadStatusTextArea;
private JScrollPane scrollPane;
private JTextField downloadLocationTextField;
private JButton downloadLocationButton;
private JPanel North;
private JPanel South;
private JPanel ProgressBarPanel;
private Map<String, JProgressBar> progressBarMap;
public DownloadFrame() {
InitComponents();
InitLayout();
AddComponents();
AddActionListeners();
setVisible(true);
setSize(700, 300);
}
private void InitComponents() {
downloadButton = new JButton("Dowload");
threadIdTextField = new JTextField(6);
downloadStatusTextArea = new JTextArea(10, 30);
scrollPane = new JScrollPane(downloadStatusTextArea, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
downloadLocationTextField = new JTextField(40);
downloadLocationButton = new JButton("...");
North = new JPanel();
South = new JPanel();
ProgressBarPanel = new JPanel();
progressBarMap = new HashMap<String, JProgressBar>();
}
private void InitLayout() {
North.setLayout(new FlowLayout());
South.setLayout(new FlowLayout());
ProgressBarPanel.setLayout(new GridLayout(10, 1));
}
private void AddComponents() {
North.add(threadIdTextField);
North.add(downloadButton);
add(North, BorderLayout.NORTH);
add(ProgressBarPanel, BorderLayout.EAST);
South.add(downloadLocationTextField);
South.add(downloadLocationButton);
add(South, BorderLayout.SOUTH);
add(scrollPane, BorderLayout.WEST);
}
private void AddActionListeners() {
downloadButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addNewProgessBar(threadIdTextField.getText());
}
});
}
public void addNewProgessBar(String threadId) {
JProgressBar progressBar = new JProgressBar();
progressBar.setStringPainted(true);
progressBarMap.put(threadId, progressBar);
drawProgessBars();
}
void drawProgessBars() {
ProgressBarPanel.removeAll();
for (JProgressBar progressBar : progressBarMap.values()) {
ProgressBarPanel.add(progressBar);
}
validate();
repaint();
}
}
}
Thanks in advance.
EDIT
Easiest solution: change
add(ProgressBarPanel, BorderLayout.EAST);
to
add(ProgressBarPanel, BorderLayout.CENTER);
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
new DownloadFrame();
}
private static class DownloadFrame extends JFrame {
private JButton downloadButton;
private JTextField threadIdTextField;
private JTextArea downloadStatusTextArea;
private JScrollPane scrollPane;
private JTextField downloadLocationTextField;
private JButton downloadLocationButton;
private JPanel North;
private JPanel South;
private JPanel ProgressBarPanel;
private Map<String, JProgressBar> progressBarMap;
public DownloadFrame() {
InitComponents();
AddComponents();
AddActionListeners();
pack();
setVisible(true);
//setSize(700, 300);
}
private void InitComponents() {
setLayout(new BorderLayout());
downloadButton = new JButton("Dowload");
threadIdTextField = new JTextField(6);
downloadStatusTextArea = new JTextArea(10, 30);
scrollPane = new JScrollPane(downloadStatusTextArea, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
downloadLocationTextField = new JTextField(40);
downloadLocationButton = new JButton("...");
North = new JPanel(new FlowLayout());
South = new JPanel(new FlowLayout());
ProgressBarPanel = new JPanel(new GridLayout(0, 1));
ProgressBarPanel.setBorder(new LineBorder(Color.black));
ProgressBarPanel.setPreferredSize(new Dimension(300,20));
progressBarMap = new HashMap<String, JProgressBar>();
}
private void AddComponents() {
North.add(threadIdTextField);
North.add(downloadButton);
add(North, BorderLayout.NORTH);
add(ProgressBarPanel, BorderLayout.EAST);
South.add(downloadLocationTextField);
South.add(downloadLocationButton);
add(South, BorderLayout.SOUTH);
add(scrollPane, BorderLayout.WEST);
}
private void AddActionListeners() {
downloadButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addNewProgessBar(threadIdTextField.getText());
}
});
}
public void addNewProgessBar(String threadId) {
JProgressBar progressBar = new JProgressBar();
progressBar.setStringPainted(true);
progressBarMap.put(threadId, progressBar);
drawProgessBars();
}
void drawProgessBars() {
ProgressBarPanel.removeAll();
for (JProgressBar progressBar : progressBarMap.values()) {
ProgressBarPanel.add(progressBar);
}
validate();
repaint();
}
}
}
well. that possible, but in your example CENTER area occupated some Rectangle, its hard to reduce/remove CENTER area to the zero Size
to the North JPanel (BorderLayout) place another JPanel and put it to the EAST (with LayoutManager would be GridLayout(1,2,10,10)) and put here two JComponents JTextField - threadIdTextField and JButton - downloadButton, there you are needed setPreferredSize 1) for JComponents (correct way) or 2) for whole JPanel (possible way too)
JScrollPane with JTextArea must be placed to the CENTER area
JPanel with JProgressBars place to EAST, but again set same PreferredSize as for JPanel with JTextField and JButton from the NORTH
SOUTH JPanel remains without changes
Please post a compilable runnable small program for the quickest best help, an SSCCE.
Suggestions include using GridLayout(0, 1) (variable number of rows, one column), or display the JProgressBars in a JList that uses a custom renderer that extends JProgressBar.
Edit 1:
I know that Andrew has already posted the accepted answer (and 1+ for an excellent answer), but I just wanted to demonstrate that this can be done readily with a JList, something like so:
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.util.Random;
import javax.swing.*;
public class EastProgressList extends JPanel {
private DefaultListModel myListModel = new DefaultListModel();
private JList myList = new JList(myListModel);
private JTextField downloadUrlField = new JTextField(10);
public EastProgressList() {
JButton downLoadBtn = new JButton("Download");
downLoadBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
downloadAction();
}
});
JPanel northPanel = new JPanel();
northPanel.add(new JLabel("File to Download:"));
northPanel.add(downloadUrlField);
northPanel.add(Box.createHorizontalStrut(15));
northPanel.add(downLoadBtn);
myList.setCellRenderer(new ProgressBarCellRenderer());
JScrollPane eastSPane = new JScrollPane(myList);
eastSPane.setPreferredSize(new Dimension(200, 100));
setLayout(new BorderLayout());
add(new JScrollPane(new JTextArea(20, 30)), BorderLayout.CENTER);
add(northPanel, BorderLayout.NORTH);
add(eastSPane, BorderLayout.EAST);
}
private void downloadAction() {
String downloadUrl = downloadUrlField.getText();
final MyData myData = new MyData(downloadUrl);
myListModel.addElement(myData);
myData.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals(MyData.VALUE)) {
myList.repaint();
if (myData.getValue() >= 100) {
myListModel.removeElement(myData);
}
}
}
});
}
private class ProgressBarCellRenderer extends JProgressBar implements ListCellRenderer {
protected ProgressBarCellRenderer() {
setBorder(BorderFactory.createLineBorder(Color.blue));
}
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
//setText(value.toString());
MyData myData = (MyData)value;
setValue(myData.getValue());
setString(myData.getText());
setStringPainted(true);
return this;
}
}
private static void createAndShowUI() {
JFrame frame = new JFrame("EastProgressList");
frame.getContentPane().add(new EastProgressList());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class MyData {
public static final int TIMER_DELAY = 300;
public static final String VALUE = "value";
protected static final int MAX_DELTA_VALUE = 5;
private String text;
private int value = 0;
private Random random = new Random();
private PropertyChangeSupport pcSupport = new PropertyChangeSupport(this);
public MyData(String text) {
this.text = text;
new Timer(TIMER_DELAY, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int deltaValue = random.nextInt(MAX_DELTA_VALUE);
int newValue = value + deltaValue;
if (newValue >= 100) {
newValue = 100;
((Timer)e.getSource()).stop();
}
setValue(newValue);
}
}).start();
}
public String getText() {
return text;
}
public int getValue() {
return value;
}
public void setValue(int value) {
int oldValue = this.value;
this.value = value;
PropertyChangeEvent pcEvent = new PropertyChangeEvent(this, VALUE, oldValue, value);
pcSupport.firePropertyChange(pcEvent);
}
public void addPropertyChangeListener(PropertyChangeListener pcListener) {
pcSupport.addPropertyChangeListener(pcListener);
}
}
This results in a GUI looking like so: