Dynamically Resize a JScrollPane? - java

I Have two files. One extends JFrame, and another Extends JPanel.
Whenever I change the size of the frame, whether it be maximizing, dragging, whatever, i want the ScrollPane to fit itself to the current size of the frame.
There's more to it, there's a top menubar and a bottom bar as well, but i left those out for simplicity.
Essentially, i want it to work like notepad.
right now, I use a ComponentListener on the frame that calls a setSize method in the the other class.
The setSize method is just:
public void resize(int x, int y)
{
textA.setPreferredSize(new Dimension(x, y-50));
areaScrollPane.setPreferredSize(new Dimension(x,y-50));
}
also, for reference:
public void componentResized(ComponentEvent e)
{
textA.resize(panel.getWidth(),panel.getHeight());
}
FYI, it extends JPanel because of the way I add it to the frame:
panel = (JPanel) this.getContentPane();
panel.setLayout(new BorderLayout());
panel.add(textA, BorderLayout.CENTER);
so what's the best way to do this?
Thanks!
Edit: Here's the scrollpane file. It's called textA in my main.
public class TextArea extends JPanel
{
JTextArea textA=new JTextArea(500,500);
JScrollPane areaScrollPane = new JScrollPane(textA);
Toolkit toolkit = Toolkit.getDefaultToolkit ();
Dimension dim = toolkit.getScreenSize();
Dimension dim2=(new Dimension((int)(dim.getWidth()),(int)(dim.getHeight()-120)));
public TextArea()
{
//textA.setLineWrap(true);
//textA.setWrapStyleWord(true);
textA.setEditable(true);
textA.setForeground(Color.WHITE);
textA.setBackground(Color.DARK_GRAY);
this.setFont(null);
areaScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
areaScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
areaScrollPane.setMinimumSize(new Dimension(300,300));
areaScrollPane.setSize(new Dimension(800,800));
textA.setPreferredSize(dim2);
areaScrollPane.setPreferredSize(dim2);
areaScrollPane.setMaximumSize(dim2);
add(areaScrollPane);
}
#Override
public void resize(int x, int y)
{
textA.setPreferredSize(new Dimension(x, y-50));
areaScrollPane.setPreferredSize(new Dimension(x,y-50));
}
}
and the main:
public class JEdit extends JFrame implements ComponentListener
{
TextArea textA=new TextArea();
JPanel panel;
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
JEdit run=new JEdit();
}
public JEdit()
{
setTitle("JEdit");
setLayout(new BorderLayout());
setSize(1100, 1000);
this.setMinimumSize(new Dimension(100,100));
//setBackground(Color.BLACK);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
System.out.println("error1");
} catch (InstantiationException ex) {
System.out.println("error2");
} catch (IllegalAccessException ex) {
System.out.println("error3");
} catch (UnsupportedLookAndFeelException ex) {
System.out.println("error4");
}
panel = (JPanel) this.getContentPane();
panel.setLayout(new BorderLayout());
//TopBar top=new TopBar();
// PositionBar posB=new PositionBar();
panel.add(textA, BorderLayout.CENTER);
// add(top,BorderLayout.NORTH);
// add(posB,BorderLayout.SOUTH);
addComponentListener(this);
setVisible(true);
}
public void componentResized(ComponentEvent e)
{
textA.resize(panel.getWidth(),panel.getHeight());
}
public void componentMoved(ComponentEvent e) {
textA.resize(panel.getWidth(),panel.getHeight());
}
public void componentShown(ComponentEvent e) {
textA.resize(panel.getWidth(),panel.getHeight());
}
public void componentHidden(ComponentEvent e) {
textA.resize(panel.getWidth(),panel.getHeight());
}
}

Regarding the code you've posted, for one get rid of all calls to setSize -- these are generally not honored when using layout managers and get rid of all of your ComponentListener stuff as it's superfluous since you are using layout managers to resize things. The biggest problem I see though is that your allow your TextArea JPanel to use its default layout, which is FlowLayout, and doing so will prevent the JScrollPane that it holds from resizing. Give this class a BorderLayout (or better simply return a JScrollPane from the class), and you're set. e.g. with quick modifications and with renaming of classes to prevent clashes with the standard Java classes,
import java.awt.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class JEdit2 extends JFrame {
TextArea2 textA = new TextArea2();
JPanel panel;
public static void main(String[] args) {
new JEdit2();
}
public JEdit2() {
setTitle("JEdit 2");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = (JPanel) this.getContentPane();
panel.add(textA, BorderLayout.CENTER);
pack(); //!! added
setLocationRelativeTo(null);
setVisible(true);
}
}
#SuppressWarnings("serial")
class TextArea2 extends JPanel {
JTextArea textA = new JTextArea(500, 500); // !! this is one friggin' huge JTextArea!
JScrollPane areaScrollPane = new JScrollPane(textA);
public TextArea2() {
textA.setEditable(true);
textA.setForeground(Color.WHITE);
textA.setBackground(Color.DARK_GRAY);
this.setFont(null);
setLayout(new BorderLayout()); //!! added
add(areaScrollPane, BorderLayout.CENTER);
}
}

By default a JFrame uses a BorderLayout (so there is no need to reset it). All you need to do is add the JScrollPane to the CENTER of the BorderLayout and it will resize automatically.
And the basic code would be:
JTextArea textArea = new JTextArea(...);
JScrollPane scrollPane = new JScrollPane();
frame.add(scrollPane, BorderLayout.CENTER);
I'm not sure why you are adding the text area to the center.
There is no need to use setPreferredSize() on any component or use a listener on any component.
If you need more help then you need to post a SSCCE.

Related

How can a JPanel be changed after added to JFrame?

I have created a subclass of JPanel to display images. I instantiate this in the constructor of a JFrame and add it to that JFrame. This works perfectly. Then I have added a button with an ActionListener to change that Image. My problem is that the JFrame won´t update although I have tried repainting etc.
The subclass of JPanel:
public class ImagePanel extends JPanel {
BufferedImage bf;
public ImagePanel(String dateiname)
{
try {
bf = ImageIO.read(new File(dateiname));
} catch (IOException e) {
e.printStackTrace();
}
}
public void paint(Graphics g)
{
g.drawImage(bf.getScaledInstance(300,200,1),0,0,null );
}
}
The JFrame is basically this
public class Hauptfenster extends JFrame {
private JButton changeImage;
private JPanel buttonPanel;
private ImagePanel ip;
public Hauptfenster {
ip = new ImagePanel("first_image.jpg");
buttonPanel = new JPanel();
buttonPanel.add(changeImage);
changeImage.addActionListener((e) -> {
ip = new ImagePanel("new_image.jpg");
ip.setVisible(true);
});
this.add(buttonPanel);
this.add(ip);
this.setVisible(true);
}
}
Why doesn´t the method in the ActionListener update the ip component in the JFrame Hauptfenster?
When you do ip = new ImagePanel("new_image.jpg"); you're creating a whole new ImagePanel that has nothing to do with your current layout. You could.
remove(ip);
ip = new ImagePanel("new_image.jpg");
add(ip);
repaint();
Another way you could do it is to just change the buffered image.
Add the following method to your image panel.
public void loadImage(String dateiname) {
try {
bf = ImageIO.read(new File(dateiname));
} catch (IOException e) {
e.printStackTrace();
}
}
Then in your action listener.
ip.loadNewImage("new_image.jpg");
ip.repaint();
You have a bunch of bad habits going on in your code though.
Such as, override paintComponent instead of paint and it should look like.
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(bf.getScaledInstance(300,200,1),0,0,null );
}
That way transparency will be handled correctly.
You shouldn't extend JFrame, you should just create a JFrame.
When you add components, you there is a layout manager involved. It's good to be aware of that and handle things accordingly. I would change your constructor to.
public Hauptfenster() {
JFrame frame = new JFrame();
ip = new ImagePanel("first_image.jpg");
buttonPanel = new JPanel();
changeImage = new JButton("change image");
buttonPanel.add(changeImage);
changeImage.addActionListener((e) -> {
frame.remove(ip);
ip = new ImagePanel("new_image.jpg");
frame.add(ip, BorderLayout.CENTER);
frame.repaint();
});
frame.add(buttonPanel, BorderLayout.SOUTH);
frame.add(ip, BorderLayout.CENTER);
frame.setVisible(true);
}
If you need more help, you'll need to actually make your example compilable. There are too many errors right now.

I'm trying to understand how to control JInternalFrames with a FocusListener

I've been looking at various questions about JInternalFrames and have tried to implement the code as suggested, but I appear to be doing something wrong. The code that I'm including here will demonstrate my problem. The three frames are created, but as you click and move them around, they will not come to the top as expected and will often times look like some sort of Escher print.
public class IntFrmTest extends JFrame {
private JPanel contentPane;
private JDesktopPane desktop;
private int formHeight=675;
private int formWidth=950;
public IntFrmTest() {
this.setTitle("Desktop");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBounds(10, 10, formWidth, formHeight);
this.setMinimumSize(new Dimension(640,480));
this.setResizable(true);
desktop = new JDesktopPane();
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(null);
setContentPane(contentPane);
this.add(BorderLayout.CENTER, desktop);
this.setVisible(true);
this.setLocationRelativeTo(null);
frmTesting frmTest1=new frmTesting(1);
frmTest1.setVisible(true);
contentPane.add(frmTest1);
frmTest1.setLocation(10,10);
frmTest1.addFocusListener(focusListener);
frmTesting frmTest2=new frmTesting(2);
frmTest2.setVisible(true);
contentPane.add(frmTest2);
frmTest2.setLocation(40,40);
frmTest2.addFocusListener(focusListener);
frmTesting frmTest3=new frmTesting(3);
frmTest3.setVisible(true);
contentPane.add(frmTest3);
frmTest3.setLocation(80,80);
frmTest3.addFocusListener(focusListener);
}
FocusListener focusListener=(new FocusListener(){
#Override
public void focusGained(FocusEvent arg0) {
JInternalFrame f = (JInternalFrame) arg0.getSource();
try {
f.setSelected(true);
f.moveToFront();
} catch (PropertyVetoException e) {
e.printStackTrace();
}
System.out.println("Got Focus "+f.getName());
}
#Override
public void focusLost(FocusEvent arg0) {
JInternalFrame f = (JInternalFrame) arg0.getSource();
try {
f.moveToBack();
f.setSelected(false);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
System.out.println("Lost Focus "+f.getName());
}
});
public class frmTesting extends JInternalFrame {
private int formHeight=375;
private int formWidth=450;
public frmTesting(int frameNo) {
this.setTitle("Internal Frame "+frameNo);
this.setName("frmTest"+frameNo);
this.setClosable(true);
this.setResizable(false);
this.setMaximizable(false);
this.setIconifiable(false);
this.setFocusable(true);
this.setSize(formWidth,formHeight);
JPanel pnlDisplay = new JPanel();
this.setContentPane(pnlDisplay);
pnlDisplay.setLayout(null);
this.setVisible(true);
}
}
public static void main(String[] args) {
IntFrmTest ift=new IntFrmTest();
}
}
I am expecting the windows to simply come to the front as they are selected but that does not happen most of the time. When clicked, they may not show as selected and often times do not come to the top.
Here's an example of how it can look:
Visually Incorrect Example
Any help explaining what I'm doing wrong would be greatly appreciated.
As usual, I spend all day trying to figure out a problem and find the answer after I've asked for help...
Perhaps someone can fill in more details, but I've been creating single forms with a desktop/contentpane combination and it's been working as expected. What I did not suss out of the docs for JInternalFrames is that it appears a JInternalFrame resides on the desktop and there is no contentpane on the main window.
When I was putting the internal frames onto the desktop/contentpane, it would not allow the frames to come to the top when selected. This led me to believe I needed to control the internal frame manually and thus the FocusListener was used.
Removing the contentpane from the mix fixes the issue and everything works as expected, which is a relief as I could not understand why it would need to be done manually. The corrected code is as follows.
public class IntFrmTest extends JFrame {
private JPanel contentPane;
private JDesktopPane desktop;
private int formHeight=675;
private int formWidth=950;
public IntFrmTest() {
this.setTitle("Desktop");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBounds(10, 10, formWidth, formHeight);
this.setMinimumSize(new Dimension(640,480));
this.setResizable(true);
desktop = new JDesktopPane();
setContentPane(desktop);
this.setVisible(true);
this.setLocationRelativeTo(null);
frmTesting frmTest1=new frmTesting(1);
frmTest1.setVisible(true);
desktop.add(frmTest1);
frmTest1.setVisible(true);
frmTesting frmTest2=new frmTesting(2);
frmTest2.setVisible(true);
desktop.add(frmTest2);
frmTesting frmTest3=new frmTesting(3);
frmTest3.setVisible(true);
desktop.add(frmTest3);
}
public class frmTesting extends JInternalFrame {
private int formHeight=375;
private int formWidth=450;
public frmTesting(int frameNo) {
super("Internal Frame "+frameNo,false,true,false,false);
this.setName("frmTest"+frameNo);
this.setSize(formWidth,formHeight);
JPanel pnlDisplay = new JPanel();
this.setContentPane(pnlDisplay);
pnlDisplay.setLayout(null);
this.setLocation(30*frameNo,30*frameNo);
this.setVisible(true);
}
}
public static void main(String[] args) {
IntFrmTest ift=new IntFrmTest();
}
}
I stumbled onto the answer when I started researching the rootpane.

Swing: JTextField inside JPanel, redraw issue

I have recently started working with Java+Swing building an UI and I currently have an issue with JTextField placed on JPanel with FlowLayout.
In my example I have a window, containing panel with button. Clicking the button adds a component derived from JPanel and containing JTextField.
The problem is that when I type in JTextField it does not get updated (does not get resized). However when I resize the window or do anything else which forces window/panel redraw, the text field being resized (just what I expect to happen automatically).
When I change base class from JPanel to JTextField it works in the way I try to achieve, but I need to have JPanel as the base class so that I can take advantages of putting child components to it.
I have checked different questions here as well as I have Googled trying to find the solution, however it did not work for me. I have tried validate/invalidate/revalidate/repaint in different combinations and for different components, as well as trying to enforce revalidation for each typed character, which does not sound as the right way for me. So far I understoon that it is something to do with Layout Managers.
Could anyone please help me with understanding how that works and what should I read about how Swing UI, layout management and redrawing is working?
Also, I would be glad if someone could help me with my particular issue with my code.
Thanks in advance!
Here is my code below:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
class TagVisual extends JPanel /*JTextField*/ {
private JTextField editField;
public TagVisual() {
FlowLayout layout = new FlowLayout();
layout.setHgap(0);
layout.setVgap(0);
setLayout(layout);
editField = new JTextField();
editField.setBackground(Color.RED);
editField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
editField.setSize(editField.getSize());
editField.revalidate();
remove(editField);
add(editField);
revalidate();
repaint();
}
});
add(editField, FlowLayout.LEFT);
}
public void place(JPanel panel) {
panel.add(this);
editField.grabFocus();
}
}
public class MainWindow {
private JPanel mainPanel;
private JButton btnPlace;
private JFrame frame;
public MainWindow(JFrame frame) {
mainPanel = new JPanel(new FlowLayout());
btnPlace = new JButton();
btnPlace.setText("Place");
mainPanel.add(btnPlace);
this.frame = frame;
btnPlace.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
TagVisual v = new TagVisual();
v.place(mainPanel);
mainPanel.revalidate();
mainPanel.repaint();
mainPanel.updateUI();
frame.revalidate();
frame.repaint();
}
});
}
public static void main(String[] args) {
JFrame frame = new JFrame("TextFieldUpdateIssue");
frame.setContentPane(new MainWindow(frame).mainPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
If i were you, i would not try to resize the textfields when the user enters some text.
I suggest you to give them a fixed size using JTextField (int columns) constructor, this will allow you to create some textfields which are "wide enough".
If you still want to make them wider when some text is entered, you can't use an ActionListener, since it will fire an event when the user presses ENTER key, not based on the text entered.
For this purpose you can register a Document Listener on your textfield's document.
You also could override getPreferredSize () method to calculate and return an appropriate size. In the example below i use a JLabel for convenience to calculate the preferred width, but you could use FontMetrics.
If you are adding multiple tags to your panel, you should also consider using a JScrollPane in order to make scrollbars appear when your panel needs more space.
See this example (i changed a bit your code because it would not compile and the general design was bad, now i think it is better, but not still good) :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class MainWindow
{
public static void main (String [] a) {
SwingUtilities.invokeLater (new Runnable () {
#Override public void run () {
try {
UIManager.setLookAndFeel (UIManager.getSystemLookAndFeelClassName ());
createAndShowGUI ();
}
catch (Exception e) {
JOptionPane.showMessageDialog (null, "An unexpected error occurred: " + e.getClass ().getSimpleName (), "Error", JOptionPane.ERROR_MESSAGE);
}
}
});
}
private static void createAndShowGUI () {
JFrame frame = new JFrame ("TextFieldUpdateIssue");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setContentPane (new MainPanel ());
frame.setExtendedState (JFrame.MAXIMIZED_BOTH);
frame.setLocationRelativeTo (null);
frame.setVisible (true);
}
}
class MainPanel extends JPanel
{
private JPanel tagsPanel;
public MainPanel () {
super (new BorderLayout (0, 10));
add (new JButton (new AbstractAction ("Add tag") {
#Override public void actionPerformed(ActionEvent e) {
addNewTag ();
}
}), BorderLayout.NORTH);
tagsPanel = new JPanel ();
tagsPanel.setLayout (new FlowLayout (FlowLayout.CENTER, 10, 0));
add (tagsPanel, BorderLayout.CENTER);
}
private void addNewTag () {
TagVisual v = new TagVisual ();
tagsPanel.add (v);
v.grabFocusOnField ();
revalidate ();
}
}
class TagVisual extends JPanel
{
private JTextField editField;
public TagVisual() {
super (new FlowLayout (FlowLayout.CENTER, 0, 0));
add (editField = createNewTextField (null), FlowLayout.LEFT);
}
private JTextField createNewTextField (String text) {
JTextField textField = new JTextField (text) {
#Override public Dimension getPreferredSize () {
Dimension d = super.getPreferredSize ();
return new Dimension (new JLabel (getText ()).getPreferredSize ().width + 10, d.height);
}
};
textField.setBackground (Color.RED);
textField.getDocument ().addDocumentListener (new DocumentListener () {
#Override public void changedUpdate (DocumentEvent e) {
revalidate ();
}
#Override public void insertUpdate (DocumentEvent e) {
revalidate ();
}
#Override public void removeUpdate (DocumentEvent e) {
revalidate ();
}
});
return textField;
}
public void grabFocusOnField () {
editField.grabFocus ();
editField.setCaretPosition (editField.getText ().length ());
}
}
Screenshot (short text):
Screenshot (Longer text):
Please review the code and note comments:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class MainWindow {
private JPanel mainPanel;
private JButton btnPlace;
public MainWindow(){
JFrame frame = new JFrame("TextFieldUpdateIssue");
//you can't use components before initializing them
btnPlace = new JButton("Button");
frame.add(btnPlace, BorderLayout.NORTH);
mainPanel = new JPanel();
frame.add(mainPanel, BorderLayout.CENTER);
btnPlace.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
TagVisual v = new TagVisual();
mainPanel.add(v); //add it to main panel
//v.place(mainPanel);
//mainPanel.revalidate();
//mainPanel.repaint();
//mainPanel.updateUI();
//frame.revalidate();
//frame.repaint();
frame.pack();
}
});
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new MainWindow();
}
}
class TagVisual extends JPanel /*JTextField*/ {
private JTextField editField;
public TagVisual() {
FlowLayout layout = new FlowLayout();
layout.setHgap(0);
layout.setVgap(0);
setLayout(layout);
editField = new JTextField();
//give it a preferred size to be used by layout manager
editField.setPreferredSize(new Dimension(150,25));
editField.setBackground(Color.RED);
editField.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//not sure what you want to do here
//not relevant to the question
}
});
add(editField, FlowLayout.LEFT);
}
}

Focus component after changing content pane of JFrame

I'm changing my JFrame's content pane and simply want to focus a JTextField in the new panel. So I'm doing this:
JPanel pNew = new JPanel();
frame.setContentPane(pNew);
frame.revalidate();
frame.repaint();
public JPanel() {
...
tf.requestFocusInWindow();
}
When I use setVisible(false) and setVisible(true) instead of revalidating and repainting my frame, I get my wished effect, but that's not the way I want to do it.
What else happens in setVisible() but revalidating and repainting?
A CardLayout is typically used to swap panels.
However, even the default implementation of CardLayout does not set focus on the panel when it is swapped. However you can check out Card Layout Focus which will allow you to request focus on the panel when it is switched.
The requestFocusInWindow() method only works on a component that is displayed in a visible frame. So you can't invoke the method in the constructor of the class.
You could use the RequestFocsListener found in Dialog Focus. It will wait until the panel is added to a visible GUI before generating the event.
I got it to work simply by putting the requestFocusInWindow() call in the button's action listener. As camickr mentioned the call needs to be made after the constructor. Here's an example program showing how I got it to work. Hope it helps!
public class PanelRevalidate {
public JFrame frame;
public MyPanel panel1, panel2;
public PanelRevalidate() {
frame = new JFrame();
panel1 = new MyPanel(1);
panel2 = new MyPanel(2);
frame.setContentPane(panel1);
panel1.getSwap().addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
frame.setContentPane(panel2);
frame.revalidate();
panel2.getTextField().requestFocusInWindow();
}
});
panel2.getSwap().addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
frame.setContentPane(panel1);
frame.revalidate();
panel1.getTextField().requestFocusInWindow();
}
});
frame.setVisible(true);
frame.setResizable(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
new PanelRevalidate();
}
});
}
}
And the MyPanel class:
public class MyPanel extends JPanel {
public JTextField tf;
public JButton swap;
public JLabel panel_label;
public MyPanel(int n) {
tf = new JTextField(25);
swap = new JButton("Swap");
panel_label = new JLabel("panel " + n);
add(tf);
add(swap);
add(panel_label);
}
public JButton getSwap() {
return swap;
}
public JTextField getTextField() {
return tf;
}
}

Place buttons and text on new line and move them to the bottom of the screen in java

I Have recently started Java programming and am trying to create a login screen. However, I cannot figure out how to create a new line to put my buttons and text on. Also, I would like to move these to the bottom right corner of the JPanel. I apologise for my poor wording and hopefully you can see what I mean from my code. Please help and thank you in advance.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CardLayoutDemo implements ItemListener {
JPanel cards;
final static String BUTTONPANEL = "Card with JButtons";
public void addComponentToPane(Container pane) {
JPanel card1 = new JPanel();
card1.add(new JLabel("Username:"));
card1.add(new JTextField("Username", 10));
card1.add(new JButton("Login")); //end line here
//New line
card1.add(new JLabel("Password:"));
card1.add(new JTextField("Password", 10));
card1.add(new JButton("Register")); //end line here
//New line
card1.add(new JCheckBox());
card1.add(new JLabel("Remember credentials"));
cards = new JPanel(new CardLayout());
cards.add(card1, BUTTONPANEL);
pane.add(cards, BorderLayout.BOTTOM_RIGHT);// Add cards to bottom right hand corner.
}
public void itemStateChanged(ItemEvent evt) {
CardLayout cl = (CardLayout)(cards.getLayout());
cl.show(cards, (String)evt.getItem());
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("Login");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CardLayoutDemo demo = new CardLayoutDemo();
demo.addComponentToPane(frame.getContentPane());
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
} catch (UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
} catch (IllegalAccessException ex) {
ex.printStackTrace();
} catch (InstantiationException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
UIManager.put("swing.boldMetal", Boolean.FALSE);
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
As shown here, you can position your top-level container in the lower, right portion of the screen. Substitute your own components for the placeholder mentioned in getPreferredSize(). Also, consider a JToolBar, which can float on many implementations.
Addendum: I want to move the buttons to the bottom right corner of the JPanel, not move the JPanel to the bottom of the screen.
Specifying FlowLayout.RIGHT for your card1 produces the result shown. Substitute your panel having CardLayout in the content pane's BorderLayout.CENTER.
public void addComponentToPane(Container pane) {
JPanel card1 = new JPanel(new FlowLayout(FlowLayout.RIGHT));
…
pane.add(new JPanel() {
#Override // placeholder for actual content
public Dimension getPreferredSize() {
return new Dimension(800, 200);
}
}, BorderLayout.CENTER);
pane.add(cards, BorderLayout.PAGE_END);
}
Addendum: Here's an update to your example.
public void addComponentToPane(Container pane) {
…
pane.add(cards, BorderLayout.PAGE_END);
}
…
private static void createAndShowGUI() {
JFrame frame = new JFrame("Login");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Move frame to lower right corner of screen
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice defaultScreen = ge.getDefaultScreenDevice();
Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds();
int x = (int) rect.getMaxX() - frame.getWidth();
int y = (int) rect.getMaxY() - frame.getHeight();
frame.setLocation(x, y);
CardLayoutDemo demo = new CardLayoutDemo();
demo.addComponentToPane(frame.getContentPane());
frame.pack();
frame.setVisible(true);
}
Suggestion:
There is no such constraint BorderLayout.BOTTOM_RIGHT with BorderLayout.
BorderLayout.SOUTH : place the component at the bottom of container
BorderLayout.EAST : Place the component at the right side of container
BorderLayout.NORTH : place the component at the top of container
BorderLayout.WEST : place the component at the right side of container
BorderLayout.CENTER: place the component at the middle of container
If you want to orient your component as you wish, where the
component will appear in order, positioned in relative to each
other, responsive with Main Container's re-size, the you need to
learn about Layout Manager first.
Learn about Event listeners. Instead of implementing an ItemListener to a JPanel/Top level class which doesn't have such listeners, either implement it to a new class with naming convention MyItemListener implements ItemListener and create a new instance to add with addItemListener(listener) function or add them inline using the means of anonymous class.
checkBox.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
// put your code
}
});
ItemListener is for the Components which works with item i.e CheckBox, ComboBox etc. There are other kind of Even listeners exist too e.g, ActionListener, MouseListener etc
Tutorial Resource:
Writing Event Listeners
Using Layout Managers
I've taken your code and modified it to the following:
package sandbox;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class LoginLayoutDemo
{
JPanel cards;
public void addComponentToPane(Container pane)
{
// Panel for text and fields
JPanel textAndFieldsPanel = new JPanel();
textAndFieldsPanel.setLayout(new GridLayout(2,2));
textAndFieldsPanel.add(new JLabel("Username ", JLabel.RIGHT));
textAndFieldsPanel.add(new JTextField("Username", 10));
textAndFieldsPanel.add(new JLabel("Password ", JLabel.RIGHT));
textAndFieldsPanel.add(new JPasswordField("password", 10));
JPanel controlsPanel = new JPanel();
controlsPanel.setLayout(new BoxLayout(controlsPanel, BoxLayout.PAGE_AXIS));
controlsPanel.add(textAndFieldsPanel);
controlsPanel.add(new JCheckBox("Remember credentials"));
JPanel bottomPanel = new JPanel();
bottomPanel.add(controlsPanel);
bottomPanel.add(new JButton("Login")); // end line here
bottomPanel.add(new JButton("Register")); // end line here
cards = new JPanel(new BorderLayout());
// cards.setLayout(new BorderLayout(cards, BoxLayout.LINE_AXIS));
cards.add(bottomPanel, BorderLayout.LINE_END);
pane.add(cards, BorderLayout.PAGE_END); // BOTTOM_RIGHT);// Add cards to bottom right hand
// corner.
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Login");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// CardLayoutDemo demo = new CardLayoutDemo();
new LoginLayoutDemo().addComponentToPane(frame.getContentPane());
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args)
{
try
{
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
} catch (UnsupportedLookAndFeelException ex)
{
ex.printStackTrace();
} catch (IllegalAccessException ex)
{
ex.printStackTrace();
} catch (InstantiationException ex)
{
ex.printStackTrace();
} catch (ClassNotFoundException ex)
{
ex.printStackTrace();
}
UIManager.put("swing.boldMetal", Boolean.FALSE);
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
You really need to learn about LayoutManagers -- the Oracle/Java site has a decent one, and there are others readily available. The thing I think most of them do least well is explain overall what the managers are for and how to design things with them - they tend to plunge right into code.
A LayoutManager is applied to a Container, and tells it how to treat the components that are added to it. FlowLayout and BoxLayout tend to lay things out in a line, either horizontal or vertical at your choice. GridLayout lays things out in a table, with all 'cells' in the grid the same size. BorderLayout has a center section and one section each for N, S, E, and W; N,S stretch horizontally, E,W stretch vertically; all four of these take their other dimension from their contained component, and the center of the BorderLayout stretches in both directions to fill the available space in its container. There is GroupLayout and GridBagLayout, etc., they are all designed to solve some problem or set of problems in UI design, and you need to learn what they do in order to design Swing UIs.
Something that some of the tutorials do but don't really explain: Each container has one layout manager, but the container can be a component in another container, and the enclosing container can have a different layout manager. That's what we've done here; the BorderLayout of the overall frame puts the panel we've built at the bottom, and the right-aligned panel within our panel puts them to the right; that's how they all get to the bottom right.
You may have meant for others of your controls to be on other lines; I'll leave doing that as an exercise for you... Good luck.
One more thing: CardLayout is for situations is where, for some reason, two or more panels are arranged on TOP of each other, i.e., one obscures the other. You have no such need in your UI that I could tell, so I eliminated the CardLayout manager.

Categories

Resources