I'm trying create a custom panel for a simple data entry dialog. I've created a custom panel which I add my labels and text fields. I'm trying to add it to a JOptionPane for display.
When I call it, my components do not display but the JOptionPane buttons do. What is the correct way of doing this?
Here is where I create my custom panel and call JOptionPane:
public class ListenCustEdit implements ActionListener {
#Override
#SuppressWarnings("empty-statement")
public void actionPerformed(ActionEvent e) {
TestPanel panel = new TestPanel();
int input = JOptionPane.showConfirmDialog(frame, panel, "Edit Customer:"
,JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
if (input == 0) {
// OK
JOptionPane.showMessageDialog(frame,"Changes savewd");
} else {
// Cancel
JOptionPane.showMessageDialog(frame, "No changes were saved");
}
}
}
Here is my custom panel class:
public class TestPanel extends JPanel {
JTextField custIdTextField;
JTextField companyTextField;
JTextField firstNameTextField;
JTextField lastNameTextField;
public TestPanel() {
initUI();
}
public final void initUI() {
// create the panel and set the layout
JPanel main = new JPanel();
main.setLayout(new GridLayout(4,4));
// create the labels
JLabel custIdLabel = new JLabel("Cust Id: ");
JLabel companyLabel = new JLabel("Company: ");
JLabel firstNameLabel = new JLabel("First Name: ");
JLabel lastNameLabel = new JLabel("Last Name: ");
// create the text fields
custIdTextField = new JTextField();
companyTextField = new JTextField();
firstNameTextField = new JTextField();
lastNameTextField = new JTextField();
// add componets to panel
main.add(custIdLabel);
main.add(custIdTextField);
main.add(companyLabel);
main.add(companyTextField);
main.add(firstNameLabel);
main.add(firstNameTextField);
main.add(lastNameLabel);
main.add(lastNameTextField);
}
You need to add the main panel to your TestPanel.
public final void initUI() {
// ...
add(main);
}
In initUI, you create a JPanel (called "main") and stuff it full of components, but don't do anything with it. You need to either add "main" to the actual instance of TestPanel, or just skip the step of creating the "main" panel altogether.
The first way:
public final void initUI() {
// ... everything as before, then
this.add(main);
}
The second way:
public final void initUI() {
this.setLayout(new GridLayout(4,4));
// create the labels
JLabel custIdLabel = new JLabel("Cust Id: ");
JLabel companyLabel = new JLabel("Company: ");
JLabel firstNameLabel = new JLabel("First Name: ");
JLabel lastNameLabel = new JLabel("Last Name: ");
// create the text fields
custIdTextField = new JTextField();
companyTextField = new JTextField();
firstNameTextField = new JTextField();
lastNameTextField = new JTextField();
// add componets to panel
this.add(custIdLabel);
this.add(custIdTextField);
this.add(companyLabel);
this.add(companyTextField);
this.add(firstNameLabel);
this.add(firstNameTextField);
this.add(lastNameLabel);
this.add(lastNameTextField);
}
(The "this."'s aren't strictly necessary, but I added them for illustration.)
Hope this helps!
You didn't add main Panel to your TestPanel instance in the constructor.
Related
I'm currently doing a quite simple GUI and was wondering how I could get the button in question out from the GridLayout and put it in its own say BorderLayout, if that's a bit vague I'll attach images to show you what I mean:
With that picture I would like the button to not be with the grid layout and for it to fill all the way across at the bottom of the program as it would in a border layout. My code is as follows:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
/**
* Write a description of class HW4GUI here.
*
* #author (your name)
* #version (a version number or a date)
*/
public class HW4GUI extends JFrame implements ActionListener
{
private JButton jbtAction;
private JTextField jtfFName;
private JTextField jtfLName;
private JTextField jtfLibNo;
private int nextLibNo;
private JPanel textPanel;
/**
* The constructor for the GUI, also initalises nextLibNo number
*/
public HW4GUI()
{
super("Adding a borrower");
makeFrame();
showFrame();
nextLibNo = 1001;
}
/**
*
*/
private void makeFrame()
{
setLayout(new GridLayout(4,0));
setResizable(false);
textPanel = new JPanel();
//textPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
textPanel.setLayout(new BorderLayout());
jtfFName = new JTextField(15);
JLabel fNLbl = new JLabel("First Name: ");
add(fNLbl);
add(jtfFName);
// add(textPanel);
fNLbl.setHorizontalAlignment(JLabel.RIGHT);
jtfFName.setEditable(true);
jtfLName = new JTextField(15);
JLabel lNLbl = new JLabel("Last Name: ");
add(lNLbl);
add(jtfLName);
//add(textPanel);
lNLbl.setHorizontalAlignment(JLabel.RIGHT);
jtfLName.setEditable(true);
jtfLibNo = new JTextField(15);
JLabel lNOLbl = new JLabel("Library Number: ");
add(lNOLbl);
add(jtfLibNo);
// add(textPanel);
lNOLbl.setHorizontalAlignment(JLabel.RIGHT);
jtfLibNo.setEditable(false);
jbtAction = new JButton("Add Borrower");
add(jbtAction, BorderLayout.SOUTH);
jbtAction.addActionListener(this);
}
/**
* displays the frame window where you can set the size of it and also other variables
*/
private void showFrame()
{
setSize(400,200);
setResizable(false);
setLocationRelativeTo( null);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent e)
{
String fn = jtfFName.getText();
String ln = jtfLName.getText();
boolean valid = true;
if (e.getActionCommand().equals("Add Borrower"))
{
if (fn.equals("") && (ln.equals("")))
{
jtfLibNo.setText("No Names");
valid = false;
}
else if (fn.equals("") )
{
jtfLibNo.setText("No First Name");
valid = false;
}
else if (ln.equals(""))
{
jtfLibNo.setText("No Last Name");
valid = false;
}
else
if (valid == true)
{
String lib = Integer.toString(nextLibNo++);
jtfLibNo.setText(lib);
jbtAction.setText("Confirm");
}
}
if (e.getActionCommand().equals("Confirm"))
{
jtfLibNo.setText("");
jbtAction.setText("Add Borrower");
}
}
}
As you have said that you want the Button outside your GridLayout, you can do:
Declare a new Panel, like mainPanel or something like that.
JPanel mp = new JPanel();
Set its layout to 3x1 using GridLayout.
mp.setlayout(new GridLayout(3,1));
Add you labels and text-fields to that panel.
mp.add(fNLbl);// and the rest.
Add this panel to your frame.
add(mp, BorderLayout.CENTER);
Then add the Button at the end, using, BorderLayout.SOUTH.
add(jbtAction, BorderLayout.SOUTH);
But as far as my knowledge goes, then your button will occupy the width of the whole frame. So, instead, you can add the button to a panel, and then add that panel to it. Like:
add( new JPanel(){{ add(jbtAction);}}, BorderLayout.SOUTH); // this is double-brace initialization.
The following code works fine:
private void makeFrame()
{
JPanel mp = new JPanel();
mp.setLayout(new GridLayout(3,1));
setResizable(false);
textPanel = new JPanel();
//textPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
textPanel.setLayout(new BorderLayout());
jtfFName = new JTextField(15);
JLabel fNLbl = new JLabel("First Name: ");
mp.add(fNLbl);
mp.add(jtfFName);
// add(textPanel);
fNLbl.setHorizontalAlignment(JLabel.RIGHT);
jtfFName.setEditable(true);
jtfLName = new JTextField(15);
JLabel lNLbl = new JLabel("Last Name: ");
mp.add(lNLbl);
mp.add(jtfLName);
//add(textPanel);
lNLbl.setHorizontalAlignment(JLabel.RIGHT);
jtfLName.setEditable(true);
jtfLibNo = new JTextField(15);
JLabel lNOLbl = new JLabel("Library Number: ");
mp.add(lNOLbl);
mp.add(jtfLibNo);
// add(textPanel);
lNOLbl.setHorizontalAlignment(JLabel.RIGHT);
jtfLibNo.setEditable(false);
jbtAction = new JButton("Add Borrower");
add(mp, BorderLayout.CENTER);
add( new JPanel(){{ add(jbtAction);}}, BorderLayout.SOUTH);
jbtAction.addActionListener(this);
}
With that picture I would like the button to not be with the grid layout and for it to fill all the way across at the bottom of the program as it would in a border layout
Then use a BorderLayout. The default layout manager for a JFrame is a BorderLayout. So you would do somethinglike:
Create a panel using a GridLayout. Add the first 5 components to this panel. Then add the panel to the "CENTER" of the frame.
Create your button. Add the button the the "PAGE_END" of the frame.
The idea of layout managers is that you can nest panels with different layouts to achieve your final layout.
I also agree, the main panel with multiple buttons should probably be a GridBagLayout as it will size each column to the width of the widest component in the column instead of making every column width identical, which will make the panel look better. Read the section from the Swing tutorial on How to Use GridBagLayout for more information and working examples.
I am using FlowLayout and trying to make JLabels and JTextField in order but I am stuck and do not know how to do it.
public class SoftwareProducts extends JPanel implements ActionListener {
JTextField ramtf;
JTextField processortf;
JTextField productIDtf;
JTextField productNametf;
JTextField productYeartf;
JTextField productPublishHousetf;
JButton CompleteOrder;
JLabel Ramlb = new JLabel("RAM:");
JLabel processorlb = new JLabel("Processor:");
JLabel productIDlb = new JLabel("Product ID");
JLabel productNamelb = new JLabel("Product Name:");
JLabel productYearlb = new JLabel("Product Year:");
JLabel PublishHouselb = new JLabel("Publish House:");
JPanel softwarePanel;
CardLayout c2 = new CardLayout();
CompleteOrder completeOrder;
public static void main(String[] args) {
new SoftwareProducts();
}
public SoftwareProducts() {
setSize(500, 300);
setLayout(new FlowLayout());
add(Ramlb);
Ramlb.setFont(new Font("Arial", 5, 28));
ramtf = new JTextField(15);
add(ramtf);
ramtf.addActionListener(this);
add(processorlb);
processortf = new JTextField(15);
processortf.addActionListener(this);
add(processortf);
add(productIDlb);
productIDtf = new JTextField(10);
productIDtf.addActionListener(this);
add(productIDtf);
add(productNamelb);
add(productNamelb);
productNametf = new JTextField(10);
productNametf.addActionListener(this);
add(productNametf);
add(productYearlb);
productYeartf = new JTextField(10);
productYeartf.addActionListener(this);
add(productYeartf);
add(PublishHouselb);
productPublishHousetf = new JTextField(10);
productPublishHousetf.addActionListener(this);
add(productPublishHousetf);
CompleteOrder = new JButton("CompleteOrder");
CompleteOrder.setSize(25, 40);
CompleteOrder.addActionListener(this);
add(CompleteOrder);
softwarePanel = new JPanel(new FlowLayout());
softwarePanel.add(Ramlb);
softwarePanel.setLayout(c2);
completeOrder = new CompleteOrder();
softwarePanel.add(new JPanel(), "empty");
softwarePanel.add(completeOrder, "completeOrder");
this.add(softwarePanel);
this.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == CompleteOrder) {
c2.show(softwarePanel, "completeOrder");
float ram = Float.parseFloat(ramtf.getText());
float processor = Float.parseFloat(processortf.getText());
int productID = Integer.parseInt(productIDtf.getText());
String productName = productNametf.getText();
int productYear = Integer.parseInt(productYeartf.getText());
String productPublishHouse = productPublishHousetf.getText();
main.softwareList.add(new Software(productID, productName, productYear, productPublishHouse));
ramtf.setText("");
System.out.println("Saved");
}
}
}
What code would result in it new lines breaks in each line? Shat should to be done to make the line breaks down in JLabel and LTextField?
These are two completely different problems and neither of them has anything to do with the LayoutManager.
For the JTextField:
Taken from the docs:
JTextField is a lightweight component that allows the editing of a single line of text
There's no way at all to add a newline to a JTextField (atleast no legit way). Use a JTextArea instead; newlines are just like in the console \n.
JLable like most other JComponents aswell can process and display HTML-code. So a newline in a JLabel would look like this:
JLabel twoLined = new JLabel("This is one line</br>And this is another one");
I have a frame that opens when you click file>new user, but the text fields are all squished together.
I'm trying to have them all stacked vertically so I use new GridLayout(3, 2) as my LayoutManager. However, the stuff for the new window is all the way at the bottom.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class App extends JFrame implements ActionListener
{
private final int WIDTH = 300;
private final int HEIGHT = 550;
private int control = 0;
String[] username = new String[10];
String[] pass = new String[10];
private String tempName;
private String tempPass;
Container con = getContentPane();
JPanel panel = new JPanel();
private JTextField name = new JTextField();
private JPasswordField password = new JPasswordField();
JMenuBar mainBar = new JMenuBar();
JMenu menu1 = new JMenu("File");
JMenu menu2 = new JMenu("Edit");
JMenuItem newUser = new JMenuItem("New User");
JButton but1 = new JButton("Log In");
JButton but2 = new JButton("test");
JLabel error = new JLabel("Login info not corret\n Or user not registered.");
JLabel success = new JLabel("Success!");
/////////////stuff for dialog///////////////////
JPanel panel2 = new JPanel();
JTextField newModalUser = new JTextField();
JPasswordField newModalPass = new JPasswordField();
JPasswordField newModalPassCon = new JPasswordField();
JButton register = new JButton("Register");
////////////////////////////////////////////////
public static void main(String[] args)
{
App frame = new App();
}
public App()
{
//just settin some stuff up
super("For The Bold");
setSize(WIDTH, HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
//setResizable(false);
setVisible(true);
//add menubar
setJMenuBar(mainBar);
mainBar.add(menu1);
menu1.add(newUser);
//background of main JFrame
setContentPane(new JLabel(new ImageIcon("//Users//ryanchampin//Desktop//GUI app//image.png")));
//test names in the arrays
username[0] = "ryan";
pass[0] = "test";
//main stuff in the middle
//panel.setBackground(Color.RED);
panel.setSize(300,300);
panel.add(name);
panel.add(password);
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS ));
panel.add(but1);
panel.add(but2);
add(panel,new GridBagConstraints());
setLayout(new GridBagLayout());
//assign action listener
but1.addActionListener(this);
newUser.addActionListener(this);
register.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
Object source = e.getSource();
tempName = name.getText();
tempPass = password.getText();
if(source == but1)
{
for(int x = 0; x < username.length; x++)
{
if(tempName.equalsIgnoreCase(username[x]) && tempPass.equals(pass[x]))
{
//display success JLabel
add(success);
System.out.println("success");
break;
}
else
{
success.setText(null);
add(error);
name.setText(null);
password.setText(null);
}
}
}
else
if(source == newUser)
{
panel.setVisible(false);
setLayout(new GridLayout(3,2));
add(panel2);
panel2.add(newModalUser);
panel2.add(newModalPass);
panel2.add(newModalPassCon);
panel2.add(register);
}
else if(source == register)
System.out.println("yay it worked");
}
}
Avoid using setSize(...) or setPreferredSize(...) if possible.
Instead let the components and their layout managers set their own sizes.
Use a CardLayout to swap views instead of what you're doing. If you do this, the CardLayout will size its container to fit all the "cards" that it has been given.
Don't forget to call pack() on the GUI after adding all components
Don't forget to call setVisible(true) after adding all components and after calling pack.
When creating new JTextFields and JPasswordFields, pass in an int for the number of columns into the constructors.
Edit
You ask:
whats pack() used for?
The pack() method tells the GUI to have all the layout managers of its constituent containers to lay out their components, and then to set the best size of the GUI after every component has been properly placed.
If you want spacing in a GridLayout, you can use the setHgap(int) and setVgap(int) methods to set the number of pixels of space that will appear between each element in the grid.
In your code, there are two ways you could do this: construct a GridLayout and call the two setter methods on it, then pass it into the setLayout(LayoutManager) method:
GridLayout layout = new GridLayout(3, 2);
layout.setHgap(5); // or whatever number of pixels you want
layout.setVgap(5); // same
setLayout(layout);
Alternatively, you could cast the LayoutManager you would get from calling getLayout() and call the two methods on it:
setLayout(new GridLayout(3, 2));
((GridLayout) getLayout()).setHgap(5);
((GridLayout) getLayout()).setVgap(5);
if you want them stacked vertically, wouldn't it be easier to keep using BoxLayout?
I am trying to make a program that reads a file chosen by the user, and after reading the file - the suffix "txt" is changed to "gif" and the file is saved as a picture (which is in the same catalogue as the file). The thing is, this picture variable gets its value in the "actionPerformed-method" and after that I want to add it to a frame in another class- but it doesn't show. Here's the code in my OptionsPane-class:
public class OptionsPane extends JComponent implements ActionListener{
private JButton buttonOne = new JButton("Alt.1");
private JButton buttonTwo = new JButton("Alt.2");
private JButton buttonThree = new JButton("Alt.3");
private int option;
private JButton buttonChoose = new JButton("Choose file");
private FileHandler filehandler;
private String picture;
private JLabel picLabel;
public OptionsPane(){
JLabel label = new JLabel("Choose optimization method", SwingConstants.CENTER);
JPanel subPanel = new JPanel();
label.setForeground(Color.CYAN);
label.setFont(new Font("Tahoma", Font.BOLD, 15));
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
this.add(label);
buttonOne.addActionListener(this);
buttonTwo.addActionListener(this);
buttonThree.addActionListener(this);
buttonChoose.addActionListener(this);
subPanel.setBackground(Color.DARK_GRAY);
subPanel.add(buttonOne);
subPanel.add(buttonTwo);
subPanel.add(buttonThree);
subPanel.add(buttonChoose);
this.add(subPanel);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == buttonOne){
option = 1;
System.out.println("You clicked button 1!");
}else if(e.getSource() == buttonTwo){
option = 2;
System.out.println("You clicked button 2!");
}else if(e.getSource() == buttonThree){
option = 3;
System.out.println("You clicked button 3!");
}else if(e.getSource() == buttonChoose){
System.out.println("hello");
option = 4;
filehandler = new FileHandler();
filehandler.read();
picture = filehandler.getFilePath().replaceFirst("txt", "gif");
picLabel = new JLabel(new ImageIcon(picture));
this.add(picLabel);
}
}
}
The frame is in the "MainFrame"-class, which looks like this at the moment:
public class MainFrame extends JFrame{
private JFrame frame = new JFrame();
private String picture;
private JLabel picLabel;
public MainFrame(){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(1300, 800));
frame.getContentPane().setBackground(Color.DARK_GRAY);
frame.setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS));
OptionsPane optionspane = new OptionsPane();
frame.add(optionspane);
frame.pack();
frame.setVisible(true);
frame.setResizable(true);
}
}
Why isn't the picture visible in the mainframe?
EDIT
It works now!
https://stackoverflow.com/a/22380387/3271504
Thank you for your help #arooaroo . I tried to write down some of what you wrote, but it still didn't work when I wanted to add an image based on what file the user had chosen (for example if the user chose file text1.txt i wanted the corresponding picture "text1.gif" to show up). With your help, the picture showed up when I typed a specific pathway with "/"-slashes, but when I chose a file and tried to load the picture from the file pathway, it didn't show and that is because it had backslashes in the pathways. This is how it should be (such an irritating problem):
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == buttonOne){
option = 1;
System.out.println("You clicked button 1!");
}else if(e.getSource() == buttonTwo){
option = 2;
System.out.println("You clicked button 2!");
}else if(e.getSource() == buttonThree){
option = 3;
System.out.println("You clicked button 3!");
}else if(e.getSource() == buttonChoose){
filehandler = new FileHandler();
filehandler.read();
filepath = filehandler.getFilePath();
picture = filepath.replaceFirst("txt", "gif");
picture = picture.replaceAll("\\\\", "/");
ImageIcon icon = new ImageIcon(picture);
mainFrame.setPicture(icon);
}
Thank you for your help!
Once you separate your GUI code in to separate classes - which is a Good Thing - you will find the eternal challenge for GUI programming is allowing for clean communication between them where there are inter-dependencies.
In this instance perhaps the simplest approach is to pass in a reference of MainFrame into OptionsPane.
Let's assume you create an additional method in MainFrame for setting the picture:
public class MainFrame extends JFrame{
// all instance vars as before
public MainFrame() {
// same as before except for this line...
OptionsPane optionspane = new OptionsPane(this);
}
public void setPicture(JLabel pictureLabel) {
// add code here for adding the picture...
// That's an exercise for yourself, or another question ;)
}
}
Then in your OptionsPane class:
....
private MainFrame mainFrame; // add a new instance var
public OptionsPane(MainFrame mainFrame) {
this.mainFrame = mainFrame;
// ... rest of the code same as before
}
#Override
public void actionPerformed(ActionEvent e) {
//...
picture = filehandler.getFilePath().replaceFirst("txt", "gif");
picLabel = new JLabel(new ImageIcon(picture));
mainFrame.setPicture(picLabel); // <-- This is where you communicate with the mainFrame instance
//...
}
EDIT
Although my original answer provided a valid and correct solution, it's clear that the OP requires a fully working example, including the code to load display the resulting image. Here's a sample program.
public class OptionsPane extends JComponent implements ActionListener {
private JButton buttonOne = new JButton("Alt.1");
private JButton buttonTwo = new JButton("Alt.2");
private JButton buttonThree = new JButton("Alt.3");
private int option;
private JButton buttonChoose = new JButton("Choose file");
private String picture;
private JLabel picLabel;
private MainFrame mainFrame;
public OptionsPane(MainFrame mainFrame) {
this.mainFrame = mainFrame;
JLabel label = new JLabel("Choose optimization method", SwingConstants.CENTER);
JPanel subPanel = new JPanel();
label.setForeground(Color.CYAN);
label.setFont(new Font("Tahoma", Font.BOLD, 15));
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
this.add(label);
buttonOne.addActionListener(this);
buttonTwo.addActionListener(this);
buttonThree.addActionListener(this);
buttonChoose.addActionListener(this);
subPanel.setBackground(Color.DARK_GRAY);
subPanel.add(buttonOne);
subPanel.add(buttonTwo);
subPanel.add(buttonThree);
subPanel.add(buttonChoose);
this.add(subPanel);
}
#Override
public void actionPerformed(ActionEvent e) {
// For sake of simplicity I'm ignoring the original button logic here
// and focussing on just getting an icon loaded in the parent frame...
ImageIcon icon = new ImageIcon("/path/to/test/image.png");
// Just pass the icon itself rather than a new label.
mainFrame.setPicture(icon);
}
}
public class MainFrame {
// No need to extend JFrame if you're using a JFrame instance variable
private JFrame frame = new JFrame();
private JLabel picLabel;
private JPanel mainPanel;
public MainFrame() {
mainPanel = new JPanel(new BorderLayout());
mainPanel.setBackground(Color.DARK_GRAY);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(1300, 800));
OptionsPane optionspane = new OptionsPane(this);
mainPanel.add(optionspane, BorderLayout.NORTH);
picLabel = new JLabel();
picLabel.setHorizontalAlignment(JLabel.CENTER);
mainPanel.add(picLabel, BorderLayout.CENTER);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setVisible(true);
frame.setResizable(true);
}
public void setPicture(ImageIcon icon) {
picLabel.setIcon(icon);
}
public static void main(String[] args) {
new MainFrame();
}
}
Note I've done a couple of things differently. Personally I always create a JPanel and set that up as the primary layer rather and add that directly to the frame rather than messing with the rootPane. And I used the BorderLayout in this example as it's much simpler.
The other thing is to add the JLabel which is to hold the picture to the GUI in the initial set up. Then you'll see I'm only changing its icon in the setPicture() method rather than adding a new JLabel on each instance.
Class SampleFiveA extends JPanel. This contains textfields, one below the other, each of which has a label on the left. All textfields will be of the same width and positioned against the right border of the panel. SampleFiveA has only one constructor that accepts the following three parameters:
ArrayList names,
ArrayList values,
int cols
I so far created the sample username password screen in GUI but now I have a problem implementing an ArrayList in JPanel one for User Name and the other for password. Kind of stuck there for hours now cant find a proper example to do it. Below is the code I commented what I need to be done using ArrayList.
public class SampleFiveA extends JPanel {
ArrayList<String> names = new ArrayList<String>(); //the text for the labels
ArrayList<String> values = new ArrayList<String>(); // the initial contents of the text fields
int col ; //the number of columns used to set the width of each textfield
public SampleFiveA()
{
JPanel p = new JPanel();
p.setLayout(new GridLayout(2,2));
JLabel lab1 = new JLabel("User Name", JLabel.LEFT);
p.add(lab1 = new JLabel("User Name"));
JTextField txt1 = new JTextField("User Name", JTextField.RIGHT);
p.add(txt1= new JTextField());
JLabel lab2 = new JLabel("Password ", JLabel.LEFT);
p.add(lab2 = new JLabel("Password"));
JPasswordField txt2 = new JPasswordField("*****",JPasswordField.RIGHT );
p.add(txt2 = new JPasswordField());
// names.add(lab1,lab2);// Not right but I want to put the label text to this arrayList
// values.add(txt1,txt2);//
add(p);
};
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.getContentPane().add(new SampleFiveA());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200,200);
frame.setVisible(true);
};
};
you can use
names.add(txt1.getText());
values.add(txt2.getText());
but maybe you should think about a better data structure, e.g. a HashMap and
hashmap.put(txt1.getText(),txt2.getText())
(and you should do this based on some event,e.g. user presses a button, not in the constructor, as otherwise the value will be the one you set before)
Here's a start for you.
It adds a FocusListener to the text fields and makes sure that the content of the ArrayList is updated with the current value when the text field looses focus.
import java.awt.GridLayout;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
public class Main extends JPanel {
ArrayList<String> names = new ArrayList<String>(); // the text for the
// labels
ArrayList<String> values = new ArrayList<String>(); // the initial contents
// of the text fields
int col; // the number of columns used to set the width of each textfield
public Main() {
JPanel p = new JPanel();
p.setLayout(new GridLayout(2, 2));
names = new ArrayList<String>();
values = new ArrayList<String>();
JLabel lab1 = new JLabel("User Name", JLabel.LEFT);
p.add(lab1);
JTextField txt1 = new JTextField("User Name", JTextField.RIGHT);
p.add(txt1);
names.add(lab1.getText());
values.add(txt1.getText());
JLabel lab2 = new JLabel("Password ", JLabel.LEFT);
p.add(lab2);
JPasswordField txt2 = new JPasswordField("*****", JPasswordField.RIGHT);
p.add(txt2);
names.add(lab2.getText());
values.add(txt2.getText());
// names.add(lab1,lab2);// Not right but I want to put the label text to
// this arrayList
// values.add(txt1,txt2);//
txt1.addFocusListener(new ArrayListFocusListener(txt1, values, 0));
txt2.addFocusListener(new ArrayListFocusListener(txt2, values, 1));
add(p);
// Start a thread to print the content of the list for 10 seconds
new Thread() {
public void run() {
for (int i = 0; i < 10; i++) {
try {
sleep(1000);
} catch (InterruptedException e) {
}
System.out.println(values);
}
}
}.start();
};
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().add(new Main());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setVisible(true);
};
class ArrayListFocusListener implements FocusListener {
JTextField textField;
ArrayList<String> backingList;
int myIndex;
public ArrayListFocusListener(JTextField textField,
ArrayList<String> backingList, int myIndex) {
this.textField = textField;
this.backingList = backingList;
this.myIndex = myIndex;
}
public void focusGained(FocusEvent e) {
}
#Override
public void focusLost(FocusEvent e) {
backingList.set(myIndex, textField.getText());
}
}
};
I'm sure what you are trying to do. You either want to put the JLabel in an ArrayList or the text of that label.
If you want to put the whole JLabel in an ArrayList, you should make a ArrayList<JLabel>. But I take it you want to get the text from the JLabel, so you should write names.add(lab1.getText());.
The constructor you have made doesn't take any parameters. The parameters you have wrote are the instance variable, meaning those are the variables any instance of that class will have. If you want to pass parameters in your constructor you should do what thasc told you.
You write:
JLabel lab1 = new JLabel("User Name", JLabel.LEFT);
p.add(lab1 = new JLabel("User Name"));
But since you are already creating the lab1 JLabel you could just write p.add(lab1).
And a final note I think SampleFiveA should better extend JFrame unless you want it to extend JPanel to use it somewhere else. If you need it to be standalone you should change that.
cheers