Positioning a button on a JPanel - swing

I am trying to set the three buttons in the middle of this JPanel which is set above another panel.
Everything is working fine, but three buttons remains at the same position, no matter what.
How can I move the three buttons in the center of the panel2? Right now the three buttons are at the center Left of the panel2.
Code for my panel is here:
public AbcGeniusPanel()
{
//this.setVisible(false);
ImageIcon[] alphabets = new ImageIcon[26];
ImageIcon[] images = new ImageIcon[26];
setBackground(Color.yellow);
//Load the images for alphabet images into the alphabets array using a for loop
for(int i = 0; i < alphabets.length; i++)
{
alphabets[i] = new ImageIcon("C:\\Users\\Dip\\Desktop\\Java Projects\\AbcGeniusApp\\src\\Alphabets\\"+(i+1)+".png");
}
//Load the images images in the IMageIcon array
for(int i = 0; i < images.length; i++)
{
images[i] = new ImageIcon("C:\\Users\\Dip\\Desktop\\Java Projects\\AbcGeniusApp\\src\\Images\\"+(i+1)+".png");
}
//Create two JPanel objects
JPanel panel = new JPanel();
JPanel panel2 = new JPanel();
//Set a layoutManager on the panel
panel.setLayout(new GridLayout(2, 13, 5, 5)); //This is good for now
//Create an array for holdoing the buttons
buttons = new JButton[26];
/
//Try passing Images inside the JButton parameter later.
for(int i = 0; i < 26; i++)
{
buttons[i] = new JButton(alphabets[i]);
}
setLayout(new BorderLayout(2,0));
panel2.setLayout(new BoxLayout(panel2, BoxLayout.X_AXIS));
//add the panel to the Border layout
add(panel,BorderLayout.SOUTH);
add(panel2);
//Add evenHandling mechanism to all the buttons
for(int k = 0; k<26; k++)
{
buttons[k].addActionListener(this);
}
for(int count1 = 0; count1<26; count1++)
{
panel.add(buttons[count1]);
}
JButton button1 = new JButton();
JButton button2 = new JButton();
JButton button3 = new JButton();
panel2.add(button1);
panel2.add(button2);
panel2.add(button3);
}

You can use the BoxLayout (it may be easier just using Box.createHorizontalBox()) but you have to put vertical glue at each end of the box. You also may want to put horizontal struts between the buttons to give them some spacing.
It will be easier to just use a FlowLayout for your buttons, which does the equivalent of what I said without the extra code. There may be a potential drawback of the layout causing a button or 2 to flow over to the next line, but with your simple application it is probably not much of a chance.
Here are the two examples. Comment out one line and Comment in (???) the other line to see a different approach to the buttons:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class AlphabetExample {
public static void main(String[] args) {
AlphabetExample alphabetExample = new AlphabetExample();
JFrame frame = alphabetExample.createGui();
frame.setVisible(true);
}
private JFrame createGui() {
JFrame frame = new JFrame("Letters!");
frame.setSize(400, 300);
Container contentPane = frame.getContentPane();
contentPane.add(setupLetters(), BorderLayout.CENTER);
// contentPane.add(setupButtonsWithBox(), BorderLayout.NORTH); // <-- with a BoxLayout
contentPane.add(setupButtonsWithFlowPane(), BorderLayout.NORTH); // <-- with a FlowLayout
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
return frame;
}
private JPanel setupLetters() {
String letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
JPanel lettersPanel = new JPanel(new GridLayout(2, 13, 5, 5));
for (char x : letters.toCharArray()) {
final String letter = String.valueOf(x);
JButton button = new JButton(letter);
button.setActionCommand(letter);
lettersPanel.add(button);
}
return lettersPanel;
}
private JComponent setupButtonsWithBox() {
Box b = Box.createHorizontalBox();
b.add(Box.createHorizontalGlue());
b.add(new JButton("Left Button"));
b.add(Box.createHorizontalStrut(5));
b.add(new JButton("Center Button"));
b.add(Box.createHorizontalStrut(5));
b.add(new JButton("Right Button"));
b.add(Box.createHorizontalGlue());
return b;
}
private JComponent setupButtonsWithFlowPane() {
JPanel panel = new JPanel(); // default layout manager is FlowLayout
panel.add(new JButton("Left Button"));
panel.add(new JButton("Center Button"));
panel.add(new JButton("Right Button"));
return panel;
}
}

This solved my problem
for(int count1 = 0; count1<3; count1++)
{
panel2.add(Box.createHorizontalGlue());
panel2.add(imageButtons[count1]);
panel2.add(Box.createHorizontalGlue());
}

Related

Jframe Jpanel - display result while window opened

I am trying to display client details in window application using Jframe. Everything is fine except that clients needs to wait until the process completed to show the result in window(Jframe).
Is there a way to show result(Jpanel.add()) dynamically after set Jframe.setVisible(true);
Note : I am new to this code
code I tried :
JFrame frame = new JFrame();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}});
JPanel panel = new JPanel();
frame.setVisible(true);
int y=100;
for (int i = 0; i < 10; i++) {
//connecting DB and fetching data #single loop may take 5 secs to complete the process
panel.add(new JLabel("Client"+i)).setBounds(50,y, 100, 30); //after added, this should display in opened window
y=y+20;
//connecting DB and fetching data
for(int clinetDetails=0;clinetDetails< 3;clinetDetails++) {
panel.add(new JLabel("ClientDetails"+clinetDetails)).setBounds(50,y, 100, 30);
y=y+20;
}
panel.add(new JLabel("Client :"+i+" Completed")).setBounds(50,y, 100, 30);
y=y+20;
// frame.pack();
}
panel.setLayout(new GridLayout(0, 1));
JScrollPane scrollPane = new JScrollPane(panel);
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.setPreferredSize(new Dimension(300, 300));
frame.pack();
You should probably use a SwingWorker, but this will give you an idea.
First you should do swing work on the EDT, so we start by creating the GUI.
static public void main(String[] args){
EventQueue.invokeLater( ()->createGui());
}
static public void createGui(){
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.setVisible(true);
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
JScrollPane scrollPane = new JScrollPane(panel);
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
frame.setPreferredSize(new Dimension(300, 300));
frame.pack();
Runnable r = ()->{
for (int i = 0; i < 10; i++) {
//connecting DB and fetching data #single loop may take 5 secs to complete the process //all of the swing work should be done on the EDT.
final String clientName = "Client"+i;
EventQueue.invokeLater( ()->{
panel.add(new JLabel( clientName ));
} );
//connecting DB and fetching data
for(int clinetDetails=0;clinetDetails< 3;clinetDetails++) {
String clientD = "ClientDetails "+clinetDetails;
EventQueue.invokeLater( ()->{
panel.add(new JLabel(clientD));
panel.add(new JLabel( clientName + " Completed" ) );
});
}
}
};
new Thread(r).start(); //starts the working thread.
}
This will start a gui, and then when the new thread starts, you'll free up the edt so that java can display your gui, then as new information is produced, it updates the gui by posting an even to the EDT.

two text fields, one input, one output

I have to complete this code with these simple measures. Cannot do anything overly complicated. I want to translate from the top input text field and output on the bottom text field. So far, it looks right, but my translation simply outputs in the same text field as my input. I am a noob, and checked my notes and textbook, and cannot figure out how to change the output to the bottom field. It just doesn't seem to be possible with this level of code. The translation is right. I think I need to modify the Translate button, but am not sure where to indicate what. It works fine if I just wanted to output in my input box. Well, here is my code so far:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Translator4 extends JFrame implements ActionListener
{
public static final int WIDTH = 500;
public static final int HEIGHT = 500;
public static final int NUMBER_OF_CHAR = 50;
private JTextField phrase;
private JTextField translatedphrase;
public static void main(String[] args)
{
Translator4 gui = new Translator4();
gui.setVisible(true);
}
public Translator4()
{
//title bar and overall size
super("Pig Latin Translator v.4.0");
setSize(WIDTH, HEIGHT);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout(3,1));
//create input text filed
JPanel namePanel = new JPanel();
namePanel.setLayout(new BorderLayout());
namePanel.setBackground(Color.WHITE);
phrase = new JTextField(NUMBER_OF_CHAR);
namePanel.add(phrase, BorderLayout.CENTER);
JLabel nameLabel = new JLabel("Enter the phrase in English to be translated:");
namePanel.add(nameLabel, BorderLayout.NORTH);
add(namePanel);
//create the buttons
JPanel buttonPanel= new JPanel();
buttonPanel.setLayout(new FlowLayout());
buttonPanel.setBackground(Color.GREEN);
JButton actionButton = new JButton("Translate");
actionButton.addActionListener(this);
buttonPanel.add(actionButton);
JButton clearButton = new JButton("Clear");
clearButton.addActionListener(this);
buttonPanel.add(clearButton);
add(buttonPanel);
//create the output text field
JPanel namePanel2 = new JPanel();
namePanel2.setLayout(new BorderLayout());
namePanel2.setBackground(Color.WHITE);
translatedphrase = new JTextField(NUMBER_OF_CHAR*2); //output will be larger so I multiplied it by 2
namePanel.add(phrase, BorderLayout.CENTER);
JLabel nameLabel2 = new JLabel("Translation:");
namePanel2.add(nameLabel2, BorderLayout.NORTH);
add(namePanel2);
}
public void actionPerformed(ActionEvent e)
{
String actionCommand = e.getActionCommand();
if (actionCommand.equals("Translate")) //when the user wants a translation, this block executes
{
String[] words=new String[100]; //takes up to 100 words
String sentence = phrase.getText(); //the user input made into a string
String newSentence=""; //the output string generated
words = sentence.split(" "); //splits based on spaces, no other punctuation allowed
for (int index=0; index< words.length; index++) //steps thru the array of words
{
char firstChar = words[index].charAt(0); //rules for vowels, 'one' becomes 'oneway'
if (firstChar=='a'||firstChar=='e'||firstChar=='i'||firstChar=='o'||firstChar=='u')
{
words[index] = words [index] + "way";
newSentence=newSentence + " " + words[index]; //adds the word just now modified to new sentence
}
else //rules for words that don't start with vowels, 'blank' becomes 'lankbay'
{
firstChar = ' ';
words[index] = (words[index]).substring(1,(words[index].length()))
+ (words[index]).charAt(0) + "ay";
newSentence=newSentence + " " + words[index]; //adds the word just now modified to new sentence
}
phrase.setText(newSentence); //sends the new sentence back for output... problem here
}
}
else if (actionCommand.equals("Clear"))
phrase.setText("");
else
phrase.setText("Unexpected error.");
}
}
but my translation simply outputs in the same text field as my input
That's because that's what you're telling it to do
phrase.setText(newSentence); //sends the new sentence back for output... problem here
So I assume, phrase is the input and translatedphrase is the output, so that would mean, to fix your immediate issue, all you need to do is replace phrase with translatedphrase
translatedphrase.setText(newSentence); //sends the new sentence back for output... no more problem
I would also suggest you change the other setText calls you're making against phrase to translatedphrase as well
This...
translatedphrase = new JTextField(NUMBER_OF_CHAR * 2); //output will be larger so I multiplied it by 2
namePanel.add(phrase, BorderLayout.CENTER);
JLabel nameLabel2 = new JLabel("Translation:");
namePanel2.add(nameLabel2, BorderLayout.NORTH);
is also an issue, as you never actually add translatedphrase to anything, you just re-add phrase to namePanel again
So, I assume it should be
translatedphrase = new JTextField(NUMBER_OF_CHAR * 2); //output will be larger so I multiplied it by 2
namePanel2.add(translatedphrase, BorderLayout.CENTER);
JLabel nameLabel2 = new JLabel("Translation:");
namePanel2.add(nameLabel2, BorderLayout.NORTH);

GridBagLayouts in GridLayout

Trying to build about this GUI in Swing:
In my MainFrame i set a GridLayout like that to achieve 1 row, 2 columns:
setLayout(new GridLayout(1, 2));
In the Left Column i figures i would need a GridBagLayout as in the right column. Normal GridLayout doesn't work anymore because i want different sizes of each row. For the left column i tried this:
GridBagConstraints gbc = new GridBagConstraints();
mapPanel = new MapPanel(map);
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridheight = 10;
add(mapPanel, gbc);
controlPanel = new JPanel();
controlPanel.add(new JButton("Test"));
controlPanel.add(new JButton("Test 2"));
controlPanel.add(new JButton("Test 3"));
controlPanel.add(new JButton("Test 4"));
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridheight = 1;
add(controlPanel, gbc);
logPanel = new LogPanel();
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = 2;
gbc.gridheight = GridBagConstraints.REMAINDER;
add(logPanel, gbc);
This however will result in everything "packed together" in the left column. It won't expand to the 100% height and 50% width the column has. How can i achieve a GUI as in the picture?
Thanks!
Look at JNodeLayout. RectNode is exactly what you Need.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import com.smartg.swing.layout.JNodeLayout;
import com.smartg.swing.layout.LayoutNode.RectNode;
public class RectNodeDemo {
public static void main(String[] args) {
String rootName = "root";
RectNode root = new RectNode(rootName);
JNodeLayout layout = new JNodeLayout(root);
layout.setHgap(1);
layout.setVgap(1);
JPanel target = new JPanel();
target.setBorder(new EmptyBorder(10, 10, 10, 10));
target.setLayout(layout);
addPanel(target, root, new Rectangle2D.Double(0, 0, .5, .5));
addPanel(target, root, new Rectangle2D.Double(0, .5, .5, .1));
addPanel(target, root, new Rectangle2D.Double(0, .6, .5, .4));
addPanel(target, root, new Rectangle2D.Double(.5, 0, .5, .9));
addPanel(target, root, new Rectangle2D.Double(.5, .9, .5, .1));
layout.syncNodes();
JFrame frame = new JFrame();
Container contentPane = frame.getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(target, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
static void addPanel(JPanel target, RectNode node, Rectangle2D r) {
JPanel p = new JPanel();
target.add(p);
p.setBorder(new LineBorder(Color.BLACK, 1));
node.add(p, r);
}
}
You could use the Relative Layout. This layout allows you to specify the relative sizes of each component.
To create your panel on the left the code would be something like:
RelativeLayout rl = new RelativeLayout(RelativeLayout.Y_AXIS);
rl.setFill( true );
JPanel left = new JPanel( rl );
left.add(panel1, new Float(50));
left.add(panel2, new Float(10));
left.add(panel3, new Float(40));
Using only GridBagLayout will suffice.
By setting gbc.gridheight = 10 you tell GridBag to use 10 rows for the component. (Similar to rowspan in HTML.) This, however, says nothing about the actual height of the component since rows don't have a fixed height. Consequently, this constraint doesn't have any effect when you're only using a single column. The name of the constraint is IMHO confusing.
Use GridBagConstraints.weightx and GridBagConstraints.weighty to specify where extra space should go. See How to Use GridBagLayout for more.
In combination with component's preferred sizes you'll be able to obtain a panel that will show your components when the panel is small and distribute extra space when the panel is 'too big'.
Though, as Andrew Thompson pointed out, using setPreferredSize() is not a very good way to go. Often, components already have their preferred size just fine as constructed. Just play around with all of GridBagConstraints and see what happens.
This might in the end be a better looking solution.

How to modify this view using GridBagLayout

I would be grateful if you could help me to modify this interface. I just started learning GridBagLayout and I want to figure out how I can implement the drawn interface using GridBagLayout()
|-----------------------------------------------|
| Playing File: name of the file | //This JLabel should cover the entire space
|-----------------------------------------------|
| 00:00:00 ----#---------------------- 00:00:00 | //This has on the left and on the right side two labels and in the middle a JSpinner
|-----------------------------------------------|
| [Open] [Play] [Pause] [Rewind] [Save] | //This line contains 5 buttons
|-----------------------------------------------|
Please find in attachment a working example
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
public class Sample extends JPanel
{
private JLabel labelFileName = new JLabel("Playing File:");
private JLabel labelTimeCounter = new JLabel("00:00:00");
private JLabel labelDuration = new JLabel("00:00:00");
private JButton buttonOpen = new JButton(" Open ");
private JButton buttonPlay = new JButton(" Play ");
private JButton buttonPause = new JButton(" Pause ");
private JButton buttonRewind = new JButton(" Rewind ");
private JButton buttonSave = new JButton(" Save ");
private JSlider sliderTime = new JSlider();
GridBagConstraints constraints = new GridBagConstraints();
public Sample()
{
setLayout(new GridBagLayout());
constraints.insets = new Insets(5, 5, 5, 5);
sliderTime.setValue(0);
constraints.gridx = 0;
constraints.gridy = 0;
constraints.gridwidth = 5;
constraints.fill = GridBagConstraints.HORIZONTAL;
add(labelFileName, constraints);
constraints.gridx = 0;
constraints.gridy = 1;
constraints.gridwidth = 1;
add(labelTimeCounter, constraints);
constraints.gridx = 1;
constraints.gridy = 1;
constraints.gridwidth = 3;
add(sliderTime, constraints);
constraints.gridx = 4;
constraints.gridy = 1;
constraints.gridwidth = 1;
add(labelDuration, constraints);
JPanel panelButtons = new JPanel(new FlowLayout(FlowLayout.LEFT, 25, 5));
panelButtons.add(buttonOpen);
panelButtons.add(buttonPlay);
panelButtons.add(buttonPause);
panelButtons.add(buttonRewind);
panelButtons.add(buttonSave);
constraints.gridx = 0;
constraints.gridy = 2;
add(panelButtons, constraints);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
runApp();
}
});
}
public static void runApp()
{
JFrame frame = new JFrame("Frame");
frame.setVisible(true);
frame.setSize(800, 200);
frame.add( new Sample());
frame.setDefaultCloseOperation
}
}
Thanks
I would strongly suggest a one column grid with three rows.
The top row can be a panel set to flowlayout, or you could drop the label in directly. It is up to you to set the size of the label. Layout managers can't do that for you.
The middle row would be a borderlayout where the spinner is set to center, and the two labels are placed at east and west.
The bottom row should be a panel set with a flowlayout. To get the buttons nicely spaced out in your diagram, can only be done with a flowlayout.
My only concern would be that the slider panel could be resized in the vertical direction. In that case you might want to ditch the GridBaglayout, and just have a borderlayout on top where the top row is center, and the bottom two rows are packed into a panel that is south.

miglayout: can't get right-alignment to work

Something's not right here. I'm trying to get the rightmost button (labeled "help" in the example below) to be right-aligned to the JFrame, and the huge buttons to have their width tied to the JFrame but be at least 180px each. I got the huge button constraint to work, but not the right alignment.
I thought the right alignment was accomplished by gapbefore push (as in this other SO question), but I can't figure it out.
Can anyone help me?
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
public class RightAlignQuestion {
public static void main(String[] args) {
JFrame frame = new JFrame("right align question");
JPanel mainPanel = new JPanel();
frame.setContentPane(mainPanel);
mainPanel.setLayout(new MigLayout("insets 0", "[grow]", ""));
JPanel topPanel = new JPanel();
topPanel.setLayout(new MigLayout("", "[][][][]", ""));
for (int i = 0; i < 3; ++i)
topPanel.add(new JButton("button"+i), "");
topPanel.add(new JButton("help"), "gapbefore push, wrap");
topPanel.add(new JButton("big button"), "span 3, grow");
JPanel bottomPanel = new JPanel();
bottomPanel.setLayout(new MigLayout("",
"[180:180:,grow][180:180:,grow]","100:"));
bottomPanel.add(new JButton("tweedledee"), "grow");
bottomPanel.add(new JButton("tweedledum"), "grow");
mainPanel.add(topPanel, "grow, wrap");
mainPanel.add(bottomPanel, "grow");
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
never mind, I got it: looks like there needs to be a gap constraint in the column spec, not at the component level:
topPanel.setLayout(new MigLayout("", "[][][]push[]", ""));
a much easier/cleaner way (IMOH) is using component constraints and doing
topPanel.add(new JButton("help"), "push, al right, wrap");
Push will push the cell out as the window stretches but you need to tell the component to bind itself to the right of the cell. You could achieve the above with the following code.
JPanel topPanel = new JPanel();
frame.setContentPane(topPanel);
for (int i = 0; i < 3; ++i)
topPanel.add(new JButton("button"+i), "");
topPanel.add(new JButton("help"), "push, al right, wrap");
topPanel.add(new JButton("big button"), "span 3, grow, wrap");
topPanel.add(new JButton("tweedledee"), "span, split2,grow, w 180, h 100");
topPanel.add(new JButton("tweedledum"), "w 180, h 100, grow");