I am making a chat in java and need to display old messages in a JPanel. I need an image and the message that was being sent/received to be displayed, each on its own row. The code that I currently have :
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel container = new JPanel();
container.setPreferredSize(new Dimension(300, 400));
// Printing five messages
for (int i = 0; i < 5; i++) {
JPanel p = new JPanel();
p.setPreferredSize(new Dimension(300, 40));
p.setBorder(BorderFactory.createLineBorder(Color.BLACK));
p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
JLabel img = new JLabel("Image : ");
JLabel txt = new JLabel("This is some text");
p.add(img);
p.add(txt);
img.setAlignmentX(Component.LEFT_ALIGNMENT);
txt.setAlignmentX(Component.LEFT_ALIGNMENT);
container.add(p);
}
f.add(container);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
Result :
Right now I am specifying the width and height of each message which is not so good as it should automatically resize to its content. I feel like there should be a good layout-manager for this but I am new to swing so help is appreciated as I do not know which one to use.
it should automatically resize to its content.
Having text that wraps to a new line is the main problem here.
One way might be to:
use vertical Box - it allows each component to have a different height
wrap the text in HTML - it will allow for the text to wrap
Something like:
import java.awt.*;
import javax.swing.*;
public class Chat extends JPanel
{
private Box messageBox = Box.createVerticalBox();
public Chat()
{
setLayout( new BorderLayout() );
add(messageBox, BorderLayout.PAGE_START);
addMessage("Short message");
addMessage("A longer message that should wrap as reqired onto another line. This should happen dynamically");
}
public void addMessage(String text)
{
JPanel messagePanel = new JPanel( new BorderLayout() );
JLabel label = new JLabel( new ImageIcon("about16.gif") );
messagePanel.add(label, BorderLayout.LINE_START);
JLabel message = new JLabel("<html>" + text + "</html>");
messagePanel.add(message);
messageBox.add(messagePanel);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Chat");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Chat());
frame.pack();
frame.setSize(200, 100);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}
Related
I am trying to set my JTextArea to take up the max horz length of the screen, so that the next thing, in this case a button, will start on a new line, but I have no clue how to do it. I have messed around by setting the size of the JTextArea to change from, say, 20 to 1000 but that does not do anything.
How can I get my textarea to take up the entire first row and then have the next item that I add to begin on the following row? Here is what I have so far...
MyFrame(){//constructor
super("Simple Calculator");
p = new JPanel();
grid = new GridLayout(4, 4, 3, 3);
p.setLayout(grid);
setSize(400, 500);
setResizable(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setUpTextScreen();
//create buttons
for(int i = 0; i < buttonValues.length; i++){
p.add(new JButton(buttonValues[i]));
}
add(p);
setVisible(true);
}
private void setUpTextScreen() {
textOnScreen = new JTextArea(7, 1000);
textOnScreen.setText("0");//default
textOnScreen.setEditable(false);
p.add(textOnScreen);
}
How can I get my textarea to take up the entire first row and then have the next item that I add to begin on the following row?
Break your layout up into logical pieces. Start with your main panel using a BorderLayout.
First I would use a JTextField for the calculator display, not a JTextArea. Then you can add the text field using: mainPanel.add(textField, BorderLayout.PAGE_START);
Then you create a JPanel using a GridLayout for the buttons. Then you add the buttons to the button panel and use: maonPanel.add(buttonPanel, BorderLayout.CENTER);
For example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class CalculatorPanel extends JPanel
{
private JTextField display;
public CalculatorPanel()
{
Action numberAction = new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
// display.setCaretPosition( display.getDocument().getLength() );
display.replaceSelection(e.getActionCommand());
}
};
setLayout( new BorderLayout() );
display = new JTextField();
display.setEditable( false );
display.setHorizontalAlignment(JTextField.RIGHT);
add(display, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout( new GridLayout(0, 5) );
add(buttonPanel, BorderLayout.CENTER);
for (int i = 0; i < 10; i++)
{
String text = String.valueOf(i);
JButton button = new JButton( text );
button.addActionListener( numberAction );
button.setBorder( new LineBorder(Color.BLACK) );
button.setPreferredSize( new Dimension(30, 30) );
buttonPanel.add( button );
InputMap inputMap = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put(KeyStroke.getKeyStroke(text), text);
inputMap.put(KeyStroke.getKeyStroke("NUMPAD" + text), text);
button.getActionMap().put(text, numberAction);
}
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("Calculator Panel");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.add( new CalculatorPanel() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Hava a look at Nested layouts, you can add one panel with a BorderLayout (there are other options too though) and add the textarea to it. Then you only need one more panel with a GridLayout that displays the buttons. This is an example: (Note that a few lines are unnecessary in this code, but they help understand layouts)
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.border.LineBorder;
public class Example extends JFrame {
Example() {//
super("Simple Calculator");
// The Main Panel where the 2 other panels will be on
JPanel mainPanel = new JPanel(new BorderLayout());
// The textarea will be inside this panel
JPanel areaPanel = new JPanel(new BorderLayout());
JTextArea area = new JTextArea(
"This is a JTextArea -Long text to show it works -Long text to show it works- -Long text to show it works- -Long text to show it works- -Long text to show it works- -Long text to show it works-");
area.setBorder(new LineBorder(Color.BLACK));
area.setWrapStyleWord(true);
area.setLineWrap(true);
// Fill the whole space of the panel with the area
areaPanel.add(area, BorderLayout.CENTER);
// The buttons will be inside this panel
JPanel buttonPanel = new JPanel(new GridLayout(4, 4, 3, 3));
for (int i = 0; i < 16; i++) { // Adding buttons
buttonPanel.add(new JButton("Button" + i));
}
// The textarea-panel should be on top of the main panel
mainPanel.add(areaPanel, BorderLayout.NORTH);
// The panel with the buttons should fill the remaining space
mainPanel.add(buttonPanel, BorderLayout.CENTER);
getContentPane().add(mainPanel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 500);
setVisible(true);
}
public static void main(String[] args) {
new Example();
}
}
You can also use html tags like:
JButton button = new JButton("<html><b><u>T</u>wo</b><br>lines</html>");
Or in any other JComponent like you got.
So you can use <BR> tag you achieve your need.
There is a specific UI that I am trying to create for a Java program and I have been having trouble choosing the adequate Layout Managers. I would like my program to have a top panel with three elements (Two JTextFields and one JButton) and a lower JPanel that has another JPanel inside. The inner panel should always be a square, centered according to its container and adapt to the maximum height or width of its container. I have tried using a ComponentAdapter to achieve the effect of always staying a square, but the program does not seem to act the way I want it to, also the top Panel seems to get squeezed to the top
JPanel maincontainer = new JPanel();
maincontainer.setLayout(new BoxLayout(maincontainer, BoxLayout.PAGE_AXIS));
JPanel jpanel2 = new JPanel();
jpanel2.setLayout(new GridLayout(0, 3));
JTextField txt = new JTextField();
txt.setFocusable(false);
JButton btn = new JButton();
btn.setFocusable(false);
JTextField txt2 = new JTextField();
txt2.setFocusable(false);
jpanel2.add(txt);
jpanel2.add(btn);
jpanel2.add(txt2);
maincontainer.add(jpanel2);
JPanel masterPane = new JPanel(new GridBagLayout());
JPanel centerPane = new JPanel();
masterPane.add(centerPane);
masterPane.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
if(masterPane.getHeight()<masterPane.getWidth())
centerPane.setSize(masterPane.getHeight(), masterPane.getHeight());
else
centerPane.setSize(masterPane.getWidth(), masterPane.getWidth());
}
});
centerPane.setBackground(Color.blue);
masterPane.add(centerPane);
maincontainer.add(masterPane);
JFrame frame = new JFrame("");
frame.getContentPane().add(maincontainer);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(true);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setMinimumSize(new Dimension(300,300));
frame.setSize(500, 500);
I would like my program to have a top panel with three elements (Two JTextFields and one JButton) and a lower JPanel that has another JPanel inside.
The easiest way to do this is to keep using the default layout manager of the frame which is a BorderLayout. You add the panel with the text fields and buttons to the BorderLayout.PAGE_START. Then you add the panel that changes dynamically to the BorderLayout.CENTER.
The inner panel should always be a square, centered according to its container and adapt to the maximum height or width of its container
The easiest way to center a component on a panel is to use a GridBagLayout on the panel. The default GridBagConstraints will cause the component to be displayed at it preferred size centered both vertically and horizontally. So you will need a wrapper panel using the GridBagLayout to contain your center panel.
You would then want to override the getPreferredSize() method of your center panel to dynamically change as the size of the parent panel changes. This is a better approach than using a ComponentListener.
Something like:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class SSCCE extends JPanel
{
SSCCE()
{
setLayout( new BorderLayout() );
JPanel top = new JPanel( new GridLayout(0, 3) );
top.add( new JTextField(10) );
top.add( new JButton("Button") );
top.add( new JTextField(10) );
add(top, BorderLayout.PAGE_START);
JPanel center = new JPanel()
{
#Override
public Dimension getPreferredSize()
{
Dimension parent = getParent().getSize();
if (parent.width < parent.height)
return new Dimension(parent.width, parent.width);
else
return new Dimension(parent.height, parent.height);
}
};
center.setBackground( Color.BLUE );
JPanel wrapper = new JPanel( new GridBagLayout() );
wrapper.add(center, new GridBagConstraints());
add(wrapper, BorderLayout.CENTER);
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SSCCE());
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
static class DragListener extends MouseInputAdapter
{
Point location;
MouseEvent pressed;
public void mousePressed(MouseEvent me)
{
pressed = me;
}
public void mouseDragged(MouseEvent me)
{
Component component = me.getComponent();
location = component.getLocation(location);
int x = location.x - pressed.getX() + me.getX();
int y = location.y - pressed.getY() + me.getY();
component.setLocation(x, y);
}
}
}
I'm new to Java, I would like to know how can I get my textarea from the main class??
This is my code:
public static void main(String[] args) {
UIManager.put("swing.boldMetal", Boolean.FALSE);
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
frame = new JFrame("Frame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GuiManager animator = new GuiManager();
frame.add(animator, BorderLayout.CENTER);
// Display the window.
frame.pack();
frame.setSize(800, 500);
frame.setVisible(true);
}
and GuiManager:
public GuiManager() {
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
// .............
// Create Scrolling Text Area in Swing
JPanel panelLabel = new JPanel();
panelLabel.setLayout(new FlowLayout()); // No content pane for JPanel.
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout()); // No content pane for JPanel.
JLabel ta1Label = new JLabel("Label One", JLabel.LEFT);
ta1Label.setAlignmentX(Component.LEFT_ALIGNMENT);
JTextArea ta = new JTextArea("", 10, 30);
ta.setLineWrap(true);
JScrollPane sbrText = new JScrollPane(ta);
sbrText.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
JLabel ta2Label = new JLabel("Label2", JLabel.RIGHT);
ta2Label.setAlignmentX(Component.RIGHT_ALIGNMENT);
JTextArea ta2 = new JTextArea("", 10, 30);
ta2.setLineWrap(true);
JScrollPane sbrText2 = new JScrollPane(ta2);
sbrText2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
panelLabel.add(ta1Label);
panelLabel.add(ta2Label);
panel.add(sbrText);
panel.add(sbrText2);
// Put everything together.
add(panelLabel);
add(panel);
setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
}
My goal is to redirect the output to these textarea, and for some output I need to redirect to the textarea on the left, but sometime I need to output on the textarea on the right. What would be the best solution to do that? Thank you.
Everything that you want to access seems to be in GuiManager. However, you put the declaration for it in a method. This means that it becomes a local variable. Once the method is finished with it's code, the variable is gone and cannot be accessed any longer.
The fix? Just make it available to all the other classes.
public static GuiManager animator = new GuiManager();
Put that where you declared all your other variables for that class, and take out the one that was located in the 'createAndShowGUI()' method.
How do I make the subpanels within my main panel stay where they are when I set one of the subpanels to be invisible?
What I have looks like:
[ (Panel1) (Panel2) (Panel3) (Panel4) ]
When I do panel3.setVisible(false) it then looks like:
[ (Panel1) (Panel2) (Panel4) ]
I would like it to look like:
[ (Panel1) (Panel2) (Panel4) ]
I am using the GridBagLayout and my mainPanel declaration looks like:
final JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
and I add an new panel like:
final JTextField valueTextField = new JTextField();
valueTextField.setPreferredSize(new Dimension(80, 25));
valueTextField.setName("Value");
c.gridx =0;
panel.add(valueTextField, c);
I'll provide more code if needed and I don't care which layout I use as long as it gets me what I want.
I suggest using a CardLayout within the individual cells, and instead of setting it to invisible, switch to an empty panel instead.
The code below demonstrates this. Within hidePanel() there are two options to hide the cell with the CardLayout route currently enabled.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class InvisiblePanels {
public static void main(String... args) throws Exception {
JFrame frame = new JFrame();
frame.setLayout(new GridBagLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
frame.add(new MyPanel(), c);
c.gridx = 1;
frame.add(new MyPanel(), c);
c.gridx = 2;
frame.add(new MyPanel(), c);
frame.pack();
frame.setVisible(true);
}
private static class MyPanel extends JPanel {
CardLayout layout;
public MyPanel() {
layout = new CardLayout();
setLayout(layout);
JButton button = new JButton("Click me");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
hidePanel();
}
});
add(button, "visible");
add(new JPanel(), "invisible");
layout.show(this, "visible");
}
public void hidePanel() {
// setVisible(false);
layout.show(this, "invisible");
}
}
}
I believe all the layout manager respect the visibility of a component and don't include invisible components in the preferred size and layout calculations.
One solution might be to wrap all your panels in a panel using the OverlayLayout:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class OverlayLayoutInvisible
{
public static void main(String[] args)
{
JPanel panel = new JPanel();
panel.add( createPanel("Button 1") );
panel.add( createPanel("Button 2") );
panel.add( createPanel("Button 3") );
panel.add( createPanel("Button 4") );
panel.add( createPanel("Button 5") );
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.add( panel );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
public static JPanel createPanel(String text)
{
JButton button = new JButton( text );
button.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Component c = (Component)e.getSource();
c.setVisible(false);
}
});
InvisibleComponent ic = new InvisibleComponent( button );
JPanel panel = new JPanel();
panel.setLayout( new OverlayLayout(panel) );
panel.add( ic );
panel.add( button );
return panel;
}
public static class InvisibleComponent extends JComponent
{
private Component master;
public InvisibleComponent(Component master)
{
this.master = master;
setAlignmentX( master.getAlignmentX() );
setAlignmentY( master.getAlignmentY() );
}
public Dimension getPreferredSize()
{
return master.getPreferredSize();
}
}
}
You might be able to tweak GridLayout (do you have an SSCCE?)
Otherwise:
Put Panel3 and Panel4 together in a single panel that you add to the GridBagLayout. Then setup the new Panel in a Layout like FlowLayout (aligned Left with a preferred size), BorderLayout, GridLayout, etc.
Hey everyone. I'm trying to make a swing GUI with a button and a label on it. im using a border layout and the label ( in the north field ) shows up fine, but the button takes up the rest of the frame (it's in the center field). any idea how to fix this?
You have to add the button to another panel, and then add that panel to the frame.
It turns out the BorderLayout expands what ever component is in the middle
Your code should look like this now:
Before
public static void main( String [] args ) {
JLabel label = new JLabel("Some info");
JButton button = new JButton("Ok");
JFrame frame = ...
frame.add( label, BorderLayout.NORTH );
frame.add( button , BorderLayout.CENTER );
....
}
Change it to something like this:
public static void main( String [] args ) {
JLabel label = new JLabel("Some info");
JButton button = new JButton("Ok");
JPanel panel = new JPanel();
panel.add( button );
JFrame frame = ...
frame.add( label, BorderLayout.NORTH );
frame.add( panel , BorderLayout.CENTER);
....
}
Before/After
Before http://img372.imageshack.us/img372/2860/beforedl1.png
After http://img508.imageshack.us/img508/341/aftergq7.png
Or just use Absolute layout. It's on the Layouts Pallet.
Or enable it with :
frame = new JFrame();
... //your code here
// to set absolute layout.
frame.getContentPane().setLayout(null);
This way, you can freely place the control anywhere you like.
Again :)
import javax.swing.*;
public class TestFrame extends JFrame {
public TestFrame() {
JLabel label = new JLabel("Some info");
JButton button = new JButton("Ok");
Box b = new Box(BoxLayout.Y_AXIS);
b.add(label);
b.add(button);
getContentPane().add(b);
}
public static void main(String[] args) {
JFrame f = new TestFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}