Swing: JTextField inside JPanel, redraw issue - java

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);
}
}

Related

How to create multiple JPanels with JTextField input?

I am currently working on my school project to practice vocabulary, I have a method in my GUI that creates new vocabulary and the name of the list, I wanted to create a button that adds more Panels with input fields just this prototype image.
My idea is that when the user clicks
AddMoreButton it will add one JPanel just like P Panel, then the user can write vocabulary to send it to my database, is it possible to create something that?, I tried looping the P panel but it did not not change, any help would be appreciated.
private JPanel SetUpCreate() {
JPanel createPanel = new JPanel();
nameListInput = new JTextField(INPUT_FIELD_WIDTH);
termInput = new JTextField(INPUT_FIELD_WIDTH);
defintionInput = new JTextField(INPUT_FIELD_WIDTH);
p = new JPanel();
doneCreate = new JButton("Done");
doneCreate.addActionListener(new DoneCreateButtonAction());
addMoreButton = new JButton("Add");
addMoreButton.addActionListener(new AddMorePanelsListener());
p.setBorder(new BevelBorder(BevelBorder.RAISED));
p.add(termInput);
p.add(defintionInput);
JScrollPane pane = new JScrollPane(p);
createPanel.add(nameListInput);
createPanel.add(p);
createPanel.add(pane);
createPanel.add(doneCreate);
return createPanel;
}
private class DoneCreateButtonAction implements ActionListener {
public DoneCreateButtonAction() {
super();
}
public void actionPerformed(ActionEvent e) {
String namelist = nameListInput.getText();
String termglosa = termInput.getText();
String defintionglosa = defintionInput.getText();
try {
if (model.createWordList(namelist) && (model.createGlosa(termglosa, defintionglosa))) {
cl.show(cardPanel, "home");
}
} catch (IOException e1) {
JOptionPane.showMessageDialog(frame, "skapelsen av listan fungerar ej.");
}
}
}
private class AddMoreButtonAction implements ActionListener {
public AddMoreButtonAction() {
super();
}
public void actionPerformed(ActionEvent e) {
}
}
What I understand from your question is that you want to add another panel every time the user clicks the Add button and the panel to add contains fields for entering a word and its definition.
I see JScrollPane appears in the code you posted in your question. I think this is the correct implementation. In the below code, every time the user clicks the Add button I create a panel that contains the fields for a single word definition. This newly created panel is added to an existing panel that uses GridLayout with one column. Hence every time a new word definition panel is added, it is placed directly below the last word panel that was added and this GridLayout panel is placed inside a JScrollPane. Hence every time a word definition panel is added, the GridLayout panel height increases and the JScrollPane adjusts accordingly.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
public class MorPanel implements ActionListener, Runnable {
private static final String ADD = "Add";
private JFrame frame;
private JPanel vocabularyPanel;
#Override
public void run() {
showGui();
}
#Override
public void actionPerformed(ActionEvent actionEvent) {
String actionCommand = actionEvent.getActionCommand();
switch (actionCommand) {
case ADD:
vocabularyPanel.add(createWordPanel());
vocabularyPanel.revalidate();
vocabularyPanel.repaint();
break;
default:
JOptionPane.showMessageDialog(frame,
actionCommand,
"Unhandled",
JOptionPane.ERROR_MESSAGE);
}
}
public JButton createButton(String text) {
JButton button = new JButton(text);
button.addActionListener(this);
return button;
}
public JPanel createButtonsPanel() {
JPanel buttonsPanel = new JPanel();
buttonsPanel.add(createButton(ADD));
return buttonsPanel;
}
private JScrollPane createMainPanel() {
vocabularyPanel = new JPanel(new GridLayout(0, 1));
vocabularyPanel.add(createWordPanel());
JScrollPane scrollPane = new JScrollPane(vocabularyPanel);
return scrollPane;
}
private JPanel createWordPanel() {
JPanel wordPanel = new JPanel();
JLabel wordLabel = new JLabel("Enter Term");
JTextField wordTextField = new JTextField(10);
JLabel definitionLabel = new JLabel("Enter Term Definition");
JTextField definitionTextField = new JTextField(10);
wordPanel.add(wordLabel);
wordPanel.add(wordTextField);
wordPanel.add(definitionLabel);
wordPanel.add(definitionTextField);
return wordPanel;
}
private void showGui() {
frame = new JFrame("Vocabulary");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.add(createButtonsPanel(), BorderLayout.PAGE_END);
frame.setSize(480, 200);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new MorPanel());
}
}
As your code is not an Minimal Reproducible Example, I cannot provide further assistance than this:
Red part: Your main JPanel with BoxLayout
Green part: another JPanel with your JTextField in it.
Purple part: JScrollPane
Blue parts: custom JPanels with 2 panes in them, one on top for the number, one on the bottom for both JTextFields and icon, so I would say GridBagLayout or BoxLayout + FlowLayout
Orange part: JPanel with GridBagLayout or FlowLayout
Each time you clic on the + icon, you just create a new instance of the custom blue JPanel and that's it.

Is it a bad idea to call pack() in JFrame.invalidate?

I've built a simple gui that adds panels based on user input. My initial problem was that when the panel was added the frame did not resize. Because it was a jpanel object that handled the user input adding a new panel to itself and therefore could not 'see' the jframe (at least I couldn't find how it could) I couldn't work out how to call repaint() or revalidate() on the parent frame from within that object. However,through trial and error I did find that this worked
JFrame jFrame = new JFrame(title){
#Override
public void invalidate(
super.invalidate();
this.pack();
}
};
But because I don't really know what goes on behind the scenes with invalidate I want to know whether this is a good idea or not (It seems kinda sketchy). Any advice would be great, thanks.
EDIT
Hope this makes the problem a bit clearer
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class TestFrame {
JFrame jframe;
NewPanel jpanel;
public TestFrame(){
jframe = new JFrame(); // without above addition frame won't resize
jpanel = new NewPanel();
jframe.add(jPanel);
jframe.pack();
jframe.setVisible(true);
}
public static void main(String [] args){
TestFrame testframe= new TestFrame();
}
}
class NewPanel extends JPanel implements ActionListener{
public NewPanel(){
JTextField textField = new JTextField (10);
textField.addActionListener(this);
this.add(textField);
}
// Adds a label when action is performed on textfield
#Overide
public void actionPerformed(ActionEvent ae){
JPanel extraPanel = new JPanel();
extraPanel.add(new JLabel("hi"));
this.add(extraPanel);
this.revalidate(); this.repaint();
}
}
Your issue is not that revalidate() or repaint() aren't working.
The issue here is that your JFrame has been pack()ed already and thus it has a preferred size set. If you want to change its size you need to call pack() on it again. Not necessarily to call it on invalidate().
I made some changes to your code to compile (typos) and I came with this:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestFrame {
JFrame jframe;
NewPanel jpanel;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new TestFrame());
}
public TestFrame(){
jframe = new JFrame(); // without above addition frame won't resize
jpanel = new NewPanel();
jframe.add(jpanel);
jframe.pack();
jframe.setVisible(true);
}
class NewPanel extends JPanel implements ActionListener{
public NewPanel(){
JTextField textField = new JTextField (10);
textField.addActionListener(this);
this.add(textField);
}
// Adds a label when action is performed on textfield
#Override
public void actionPerformed(ActionEvent ae){
System.out.println("WOLOLO");
JPanel extraPanel = new JPanel();
extraPanel.add(new JLabel("hi"));
this.add(extraPanel);
this.revalidate();
this.repaint();
jframe.pack();
}
}
}
Another way to solve this is to override getPreferredSize method from the JPanel:
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
And you can delete jframe.pack() in the previous code.

Run new GUI window from an event of another class

I have 2 classes. Both implements runnable to create the GUI. The first one is the main, and the second one is the secondary class.
I want within the actionlistener of the main class to startup the secondary class.
Here is the code (the two classes are separated files):
public class Main implements Runnable
{
private JTextField txt1, txt2;
private JLabel lbl1, lbl2;
public void run()
{
JFrame frame = new JFrame("Secondary");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container pane = frame.getContentPane();
JPanel background = new JPanel();
background.setLayout(new BoxLayout(background, BoxLayout.LINE_AXIS));
.........
// Horizontally adding the textbox and button in a Box
Box box = new Box(BoxLayout.Y_AXIS);
......
background.add(box);
pane.add(background);
frame.pack();
frame.setVisible(true);
}
private class SListener implements ActionListener
{
public void actionPerformed(ActionEvent a)
{
Secondary s = new Secondary();
}
}
public static void main (String[] args)
{
Main gui = new Main();
SwingUtilities.invokeLater(gui);
}
}
public class Secondary implements Runnable
{
private JTextField txt1, txt2;
private JLabel lbl1, lbl2;
public Secondary()
{
Secondary gui = new Secondary();
SwingUtilities.invokeLater(gui);
}
public void run()
{
JFrame frame = new JFrame("Secondary");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container pane = frame.getContentPane();
JPanel background = new JPanel();
background.setLayout(new BoxLayout(background, BoxLayout.LINE_AXIS));
.........
// Horizontally adding the textbox and button in a Box
Box box = new Box(BoxLayout.Y_AXIS);
......
background.add(box);
pane.add(background);
frame.pack();
frame.setVisible(true);
}
}
I want to keep the code in two files, I don't want to mixed the two classes in one file.
As you can see from the code, in the Secondary class, in it's constructor I create an Instance of the Secondary class and I run the gui so that when the Instance of this class is created in the Main class, to run the gui.
Unfortunately this technique is not working.
Any ideas?
Thanks
The following line are complety wrong:
public Secondary(){
Secondary gui = new Secondary();
SwingUtilities.invokeLater(gui);
}
Each time you call new Secondary() somewhere in your code, the above code will be triggered, which in turn calls new Secondary() again, and again, and again, ... and your program is blocked.
You probably want to replace it either by
public Secondary(){
SwingUtilities.invokeLater(this);
}
which will avoid the loop, but this is weird behaviour for a constructor.
It makes much more sense to switch to an empty constructor (or delete it all together)
public Secondary(){
}
and rewrite your listener to
public void actionPerformed(ActionEvent a){
Secondary s = new Secondary();
SwingUtilities.invokeLater( s );
}
I would recommend that you completely re-design your program. I find that it is most helpful to gear my GUI's towards creation of JPanels, not top level windows such as JFrame, which can then be placed into JFrames or JDialogs, or JTabbedPanes, or swapped via CardLayouts, wherever needed. I find that this greatly increase the flexibility of my GUI coding, and is exactly what I suggest that you do. So...
Your first class creates a JPanel that is then placed into a JFrame.
In the first class's ActionListener, create an instance of the 2nd class, place it into a JDialog (not a JFrame), and then display it.
For example,
import java.awt.Component;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class TwoWindowEg {
public TwoWindowEg() {
// TODO Auto-generated constructor stub
}
private static void createAndShowGui() {
GuiPanel1 mainPanel = new GuiPanel1();
JFrame frame = new JFrame("Main GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class GuiPanel1 extends JPanel {
private static final int PREF_W = 800;
private static final int PREF_H = 650;
private GuiPanel2 guiPanel2 = new GuiPanel2(); // our second class!
private JDialog dialog = null; // our JDialog
public GuiPanel1() {
setBorder(BorderFactory.createTitledBorder("GUI Panel 1"));
add(new JButton(new LaunchNewWindowAction("Launch New Window")));
add(new JButton(new DisposeAction("Exit", KeyEvent.VK_X)));
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class LaunchNewWindowAction extends AbstractAction {
public LaunchNewWindowAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
if (dialog == null) {
// get the Window that holds this JPanel
Window win = SwingUtilities.getWindowAncestor(GuiPanel1.this);
dialog = new JDialog(win, "Second Window", ModalityType.APPLICATION_MODAL);
dialog.add(guiPanel2);
dialog.pack();
}
dialog.setVisible(true);
}
}
}
class GuiPanel2 extends JPanel {
public GuiPanel2() {
setBorder(BorderFactory.createTitledBorder("GUI Panel 1"));
add(new JLabel("The second JPanel/Class"));
add(new JButton(new DisposeAction("Exit", KeyEvent.VK_X)));
}
}
class DisposeAction extends AbstractAction {
public DisposeAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
Component comp = (Component) e.getSource();
Window win = SwingUtilities.getWindowAncestor(comp);
win.dispose();
}
}
Alternatively, you could swap JPanel "views" using a CardLayout, but either way, you will want to avoid showing two JFrames. Please have a look at The Use of Multiple JFrames, Good/Bad Practice?.

JButton changes size

I have a JFrame, and whenever I switch from one JFrame using a JButton it starts out normally, but whenever I create a new instance of the first JFrame, the JButton is in an incorrect location and is the wrong size.
Example on startup
and when another one is created
Code:
public class Menu extends JFrame implements Runnable {
private static final long serialVersionUID = 1L;
public static int Number_of_Participants = 0;
protected JPanel window = new JPanel();
double p;
private JButton Participants;
private Rectangle rParticipants;
protected int Button_width = 240;
protected int Button_height = 48;
boolean running = false;
Thread thread;
JFrame frame = new JFrame();
public Menu() {
window.setBackground(Color.BLUE);
frame.setSize(new Dimension(800, 600));
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.getContentPane().add(window);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Image image = null;
try {
image = ImageIO.read(new File("res/BG.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
generateFiles();
drawButtons();
startMenu();
frame.repaint();
}
public void drawButtons() {
rParticipants = new Rectangle(520, 12, Button_width, Button_height);
Participants = new JButton("A");
Participants.setBounds(rParticipants);
window.add(Participants);
Participants.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.dispose();
new Participant(Number_of_Participants);
}
});
}
}
Participant.java extends Menu.java
int Participant_ID;
public Participant(int Participant_ID) {
super();
this.Participant_ID = Participant_ID;
}
makes a JButton that goes back to Menu.java
As mentioned in the comment, your problem is most likely related to the call to setVisible(true). This should always be the LAST call in the constructor. Particularly, it should only be called AFTER all components have been added to the frame.
Apart from that, from the code that you posted, it seems like you want to switch through a seqence of frames, starting with a "main" menu, and then going through one frame for each "Participant". This intention could already be considered as questionable, because closing and disposing a JFrame just in order to create a new one does not seem to be very elegant. Most likely, a more elegant solution would be possible with a CardLayout : http://docs.oracle.com/javase/tutorial/uiswing/layout/card.html
However, some general hints:
Create the GUI on the Event Dispatch Thread
Don't extend JFrame. Instead, create a JFrame and fill it as needed
Don't implement Runnable with your top level class
Obey the standardJavaNamingConventions!
Don't try to do manual layouts with setBounds
This code is still not "beautiful", but at least shows how the goal of switching through several frames might be achieved, taking into account these points
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MenuExample
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
JPanel mainMenuPanel = new MainMenuPanel();
createAndShowFrame(mainMenuPanel);
}
});
}
static void createAndShowFrame(JPanel panel)
{
JFrame frame = new JFrame();
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(800, 600));
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
static JButton createNextParticipantButton(
final JComponent container, final int nextID)
{
JButton nextParticipantButton = new JButton("New Participant");
nextParticipantButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
Window window =
SwingUtilities.getWindowAncestor(container);
window.dispose();
ParticipantPanel participantPanel =
new ParticipantPanel(nextID);
createAndShowFrame(participantPanel);
}
});
return nextParticipantButton;
}
}
class MainMenuPanel extends JPanel
{
public MainMenuPanel()
{
setBackground(Color.BLUE);
add(MenuExample.createNextParticipantButton(this, 0));
}
}
class ParticipantPanel extends JPanel
{
private final int participantID;
public ParticipantPanel(int participantID)
{
this.participantID = participantID;
add(new JLabel("Add the contents for participant "+participantID));
add(MenuExample.createNextParticipantButton(this, participantID+1));
}
}

How to set the width of a JTextField at runtime?

Can someone please help me how to set the width of a JTextField at runtime? I want my text field to be resized on runtime. It will ask the user for the length, then the input will change the width of the text field.
if(selectedComponent instanceof javax.swing.JTextField){
javax.swing.JTextField txtField = (javax.swing.JTextField) selectedComponent;
//txtField.setColumns(numInput); //tried this but it doesn't work
//txtField.setPreferredSize(new Dimension(numInput, txtField.getHeight())); //also this
//txtField.setBounds(txtField.getX(), txtField.getY(), numInput, txtField.getHeight());
//and this
txtField.revalidate();
}
I am using null layout for this, since I'm on edit mode.
You simply need to use jTextFieldObject.setColumns(int columnSize). This will let you increase it's size at runtime. The reason why you couldn't do it at your end is the null Layout. That is one of the main reasons why the use of null Layout/Absolute Positioning is discouraged. Here is a small example for trying your hands on :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JTextFieldExample
{
private JFrame frame;
private JPanel contentPane;
private JTextField tfield;
private JButton button;
private int size = 10;
private ActionListener action = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
String input = JOptionPane.showInputDialog(
frame, "Please Enter Columns : "
, String.valueOf(++size));
tfield.setColumns(Integer.parseInt(input));
contentPane.revalidate();
contentPane.repaint();
}
};
private void createAndDisplayGUI()
{
frame = new JFrame("JTextField Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = new JPanel();
contentPane.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 5));
tfield = new JTextField();
tfield.setColumns(size);
JButton button = new JButton("INC Size");
button.addActionListener(action);
contentPane.add(tfield);
contentPane.add(button);
frame.getContentPane().add(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new JTextFieldExample().createAndDisplayGUI();
}
});
}
}
For absolute positioning you need to call setSize() on the JTextField in order to attain the result, though you should always keep in mind the reason why this approach is discouraged, as given in the Java Doc's first paragraph:
Although it is possible to do without a layout manager, you should use a layout manager if at all possible. A layout manager makes it easier to adjust to look-and-feel-dependent component appearances, to different font sizes, to a container's changing size, and to different locales. Layout managers also can be reused easily by other containers, as well as other programs.
I got the text field to resize just by using setBounds. Check out the following example:
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Resize extends JFrame{
public JTextField jtf = new JTextField();
public Resize(){
//frame settings
setTitle("Resizable JTextField");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
setSize(new Dimension(600,400));
setResizable(false);
//init and add text field to the frame
add(jtf);
jtf.setBounds(20,50,200,200);
//button to change text field size
JButton b = new JButton("Moar.");
add(b);
b.setBounds(20,20,b.getPreferredSize().width,b.getPreferredSize().height);
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent evt){
jtf.setBounds(20,50,jtf.getSize().width+10,jtf.getSize().height); //THIS IS WHERE THE RESIZING HAPPENS
}
});
setVisible(true);
}
public static void main(String[] args){
Resize inst = new Resize();
}
}
"Fun" little run-it-yourself solution:
public static void main(String[] args) {
JFrame frame = new JFrame();
JTextField jTextField = new JTextField("Alice");
JPanel panel = new JPanel();
JButton grow = new JButton("DRINK ME");
JButton shrink = new JButton("EAT ME");
panel.add(jTextField);
panel.add(grow);
panel.add(shrink);
frame.add(panel);
frame.setVisible(true);
frame.pack();
grow.addActionListener(l -> resize(frame, jTextField, 2));
shrink.addActionListener(l -> resize(frame, jTextField, 0.5f));
}
private static void resize(JFrame frame, Component toResize, float factor) {
System.out.println(toResize.getPreferredSize());
toResize.setPreferredSize(new Dimension((int)(toResize.getPreferredSize().width * factor),
(int)(toResize.getPreferredSize().height * factor)));
toResize.setFont(toResize.getFont().deriveFont(toResize.getFont().getSize() * factor));
frame.pack();
}
Attention: Please note that the consumption of too much cake can kill you.

Categories

Resources