How to set the width of a JTextField at runtime? - java

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.

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.

Java FlowLayout

I am writing some Java code that allows the user to see a frame with JLabel, JTextField and JButton.
I want the JLabel to be called "Count" and I have a problem with FlowLayout.
I want the interface to look like this:
Instead, I have this:
This is my code:
package modul1_Interfate_Grafice;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Exercitiu04 implements ActionListener {
private JFrame frame;
private JLabel labelCount;
private JTextField tfCount;
private JButton buttonCount;
private int count = 0;
public void go() {
frame = new JFrame("Java Counter");
labelCount = new JLabel("Counter");
labelCount.setLayout(new FlowLayout());
frame.getContentPane().add(BorderLayout.CENTER, labelCount);
tfCount = new JTextField(count + " ", 10);
tfCount.setEditable(false);
labelCount.add(tfCount);
buttonCount = new JButton("Count");
labelCount.add(buttonCount);
buttonCount.addActionListener(this);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(350, 150);
frame.setLocation(400, 200);
}
#Override
public void actionPerformed(ActionEvent event) {
count++;
tfCount.setText(count + "");
}
public static void main(String[] args) {
Exercitiu04 a = new Exercitiu04();
a.go();
}
}
Solve it.
Instead of labelCount.setLayout(new FlowLayout());` i should have had
frame.setLayout(new FlowLayout());
From description of JLabel class,
JLabel is:
A display area for a short text string or an image, or both.
But here: labelCount.add(tfCount) and here labelCount.add(buttonCount) you're trying to put a textfield and a button into a label. In this case, positions of button and textfield are controlled by FlowLayout but position of the text in the label is not.
Instead of this, you should put all of your elements in common JPanel, like this:
...
frame = new JFrame("Java Counter");
frame.setLayout(new BorderLayout());
JPanel wrapper = new JPanel(); // JPanel has FlowLayout by default
labelCount = new JLabel("Counter");
labelCount.setLayout(new FlowLayout());
wrapper.add(labelCount);
tfCount = new JTextField(count + " ", 10);
tfCount.setEditable(false);
wrapper.add(tfCount);
buttonCount = new JButton("Count");
buttonCount.addActionListener(this);
wrapper.add(buttonCount);
frame.add(BorderLayout.CENTER, wrapper);
...
And, like MasterBlaster said, you should put swing methods in EDT.
There are only two things you should know about FlowLayout:
a) It is a default layout manager of the JPanel component
b) It is good for nothing.
This trivial layout cannot be achieved with FlowLayout.
When doing layouts in Swing, you should familiarize yourself
with some powerful layout managers. I recommend MigLayout and
GroupLayout.
package com.zetcode;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import net.miginfocom.swing.MigLayout;
/*
Simple UI with a MigLayout manager.
Author Jan Bodnar
Website zetcode.com
*/
public class MigLayoutCounterEx extends JFrame {
public MigLayoutCounterEx() {
initUI();
}
private void initUI() {
JLabel lbl = new JLabel("Counter");
JTextField field = new JTextField(10);
JButton btn = new JButton("Count");
createLayout(lbl, field, btn);
setTitle("Java Counter");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void createLayout(JComponent... arg) {
setLayout(new MigLayout());
add(arg[0]);
add(arg[1]);
add(arg[2]);
pack();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
MigLayoutCounterEx ex = new MigLayoutCounterEx();
ex.setVisible(true);
});
}
}
The example is trivial. You just put the three components into the
cells.
Screenshot:
You shouldn't use setSize when dealing with FlowLayout. Instead use pack(). It makes the window just about big enough to fit all your components in. That should tidy things up for you

JLabel does not appear in the JFrame

I am having trouble implementing JLabel with JFrame. The program needs to show either "Hello" or "World" in the center of the screen when the button "study" is pressed. Also with this being a flashcard program, when study is pressed a word is placed on the middle of the screen and the program is suppose to read from the text field for the user input and print whether it is right or wrong. The problem is that the program is reading the text field after study is pressed so it is printing false before the user can input a answer.
Can someone briefly explain why this is not working and what I can do to fix this issue?
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JButton;
public class NoteCardGUI implements ActionListener {
public static JFrame frame;
public static JPanel panel;
public static JLabel label;
private NoteCard ex;
private JButton study;
public static Box box1 = new Box(), box2 = new Box(), box3 = new Box();
public NoteCardGUI() {
ex = new NoteCard("Hello", "World");
frame = new JFrame("Flash Card");
panel = new JPanel();
study = new JButton("Study");
study.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String resp = NoteCard.getResponse(ex);
String chal = NoteCard.getChallenge(ex);
String a = text.getText();
label = new JLabel(chal, label.CENTER);
label.setAlignmentX(0);
label.setAlignmentY(0);
frame.add(label, BorderLayout.SOUTH);
frame.revalidate();
if(resp.compareTo(a) == 0)
{
label = new JLabel("Correct!");
}
label = new JLabel("Incorrect");
}
});
panel.add(study);
frame.add(panel);
frame.setSize(500, 500);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
new NoteCardGUI();
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
You are adding the label to your frame, but you already have added a JPanel on top of the frame. The solution is to add the label to the panel instead of the frame.
So change: frame.add(label); to panel.add(label);
By default, a JFrame (or rather, its content pane) has BorderLayout. This means that if you add components to it without specifying a constraint, they will be added at the CENTER. But you can't add more than one element at any of the BorderLayout's regions.
So in order for this to work, you need to add the label somewhere else other than the center, or have the panel added with some other, explicit region.
So if you change the add, for example, to:
frame.add(label, BorderLayout.NORTH);
It will work - but you must not forget to also add:
frame.revalidate();
Whenever you add components to your GUI, you should call this when you've added them all, in order for it to rebuild the hierarchy of components as needed.
Another option would be to change the layout manager of the Frame, or to add to the panel.

How can I append a JTextArea from a method that doesn't contain the JTextArea?

I'm making some test code to practice OOP, and I want to append a JTextArea from the "writeToArea" to the "initialize" method where the JTextArea is defined and initialized. I already tried to directly call the "output" variable, but this returns an "output cannot be resolved" error. I want so that whenever I call the "writeToArea" method in the main class, I'll be able to add lines to the "output" JTextArea in the "initialize" method.
Here's the main class:
public class Pangea {
public static void main(String[] args) {
UI.initialize();
UI.writeToArea();
}
}
Here's the initialize class:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class UI {
static void initialize() {
System.out.println("Initializing GUI.");
JFrame frame = new JFrame();
Font myFont = new Font("Courier", Font.BOLD, 14);
JTextField input = new JTextField("");
JTextArea output = new JTextArea("Initiated Succesfully.");
output.setWrapStyleWord(true);
output.setLineWrap(true);
input.setFont(myFont);
output.setFont(myFont);
input.setForeground(Color.WHITE);
output.setForeground(Color.WHITE);
input.setBackground(Color.BLACK);
input.setCaretColor(Color.WHITE);
output.setBackground(Color.BLACK);
output.setEditable(false);
JScrollPane jp = new JScrollPane(output);
frame.setTitle("PANGEA RPG [0.01 ALPHA][WIP]");
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(input, BorderLayout.SOUTH);
frame.add(jp, BorderLayout.CENTER);
frame.pack();
frame.setSize(800, 500);
frame.setVisible(true);
System.out.println("GUI Initialized.");
}
static void writeToArea() {
System.out.println("\"writeToArea\" running.");
output.append("Hello!");
System.out.println("\"writeToArea\" finished.");
}
}
I've tried to do something similar to this: Updating jtextarea from another class but it didn't work. If anyone has any suggestions I'd be very thankful.
The main error in your code is the lack of OOP design. Making all static is poor design.
Also swing is event based, so you should append text to the textArea when an event happens. See the example i write for you.
public class UI {
private JPanel panel;
private JTextArea output;
public UI(){
initialize();
}
private void initialize() {
panel = new JPanel();
Font myFont = new Font("Courier", Font.BOLD, 14);
final JTextField input = new JTextField(""); // must be declared final cause you use it in anonymous class, you can make it instance variable if you want to as textArea
//add an actionListener then when you press enter this will write to textArea
input.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent evt){
writeToArea(input.getText());
}
});
output = new JTextArea("Initiated Succesfully",50,100);// let the component determinate its preferred size.
output.setWrapStyleWord(true);
output.setLineWrap(true);
input.setFont(myFont);
output.setFont(myFont);
input.setForeground(Color.WHITE);
output.setForeground(Color.WHITE);
input.setBackground(Color.BLACK);
input.setCaretColor(Color.WHITE);
output.setBackground(Color.BLACK);
output.setEditable(false);
JScrollPane jp = new JScrollPane(output);
panel.setLayout(new BorderLayout());
panel.add(input, BorderLayout.SOUTH);
panel.add(jp, BorderLayout.CENTER);
}
private void writeToArea(String something) {
System.out.println("\"writeToArea\" running.");
output.append(something);
System.out.println("\"writeToArea\" finished.");
}
public JPanel getPanel(){
return panel;
}
}
And in your client code
public class Pangea {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
createAndShowGUI();
}
});
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event dispatch thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
System.out.println("Initializing GUI.");
JFrame frame = new JFrame();
frame.setTitle("PANGEA RPG [0.01 ALPHA][WIP]");
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Add contents to the window.
frame.add(new UI().getPanel());
frame.pack();//sizes the frame
frame.setVisible(true);
System.out.println("GUI Initialized.");
}
}
Here you have a tutorial with better examples than this How to Use Text Areas
I remove your setSize and use pack()
The pack method sizes the frame so that all its contents are at or
above their preferred sizes. An alternative to pack is
to establish a frame size explicitly by calling setSize or setBounds
(which also sets the frame location). In general, using pack is
preferable to calling setSize, since pack leaves the frame layout
manager in charge of the frame size, and layout managers are good at
adjusting to platform dependencies and other factors that affect
component size.
Read the section from the Swing tutorial on How to Use Text Areas. It will show you how to better structure your code so that you don't use static methods and variables everywhere.
Once you have a panel that has a reference to the text area you can add methods that allow you to update the text area on the panel.

Custom JLabel Cleanup

I need to clean my labelResult each time on textField Action, but on the first time it adds 'null' in front of string and then - prints new string right after. Please help.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Frame extends JFrame implements ActionListener {
boolean isDirect = true;
String[] typeStr = {"direct", "invert"};
JLabel labelTip = new JLabel("Choose 'direct' OR 'invert' to print your next line in direct order or inverted respectively.");
JTextField textField = new JTextField("Some text!", 40);
JComboBox comboBox = new JComboBox(typeStr);
EventProcessing eventProcessing = new EventProcessing();
JLabel labelResult = new JLabel();
public Frame() {
setLayout(new BorderLayout());
getContentPane().add(labelTip, BorderLayout.PAGE_START);
getContentPane().add(comboBox, BorderLayout.CENTER);
getContentPane().add(textField, BorderLayout.AFTER_LINE_ENDS);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
textField.addActionListener(this);
pack();
}
public void actionPerformed(ActionEvent e) {
getContentPane().remove(labelResult);
labelResult = new JLabel();
labelResult.setText("");
if (!(comboBox.getSelectedItem()).equals("direct")) {
isDirect = false;
}
else {
isDirect = true;
}
labelResult.setText(eventProcessing.action(isDirect, textField.getText()));
getContentPane().add(labelResult, BorderLayout.PAGE_END);
pack();
}
}
#Tim I know that in official tutorial about JComboBox is used ActionListener, but for any of actions from JComboBox to the GUI is better look for ItemListener, there you are two states (always be called twice, but you can filtering between thes two options SELECTED / DESELECTED by wraping to the if ... else)
and your code should be only
Runnable doRun = new Runnable() {
#Override
public void run() {
labelResult.setText(eventProcessing.action(isDirect, textField.getText()));
add(labelResult, BorderLayout.PAGE_END);
//1) this.pack(); if you want to re-layout with effect to size of JFrame too
//2a revalidate();
//2b plus in most cases
//2b repaint(); relayout Container with fitting JComponents inside Container,
//2b but without resize of JFrame
}
};
SwingUtilities.invokeLater(doRun);
Without the code to EventProcessing.action() it's hard to determine, but I would guess you attempt to concatenate two strings, the first of which is null. Null strings get converted to the literal string "null."

Categories

Resources