This code, when run, will make a window but not at the specified dimensions. What is wrong with it?
import javax.swing.*;
import java.awt.*;
public class Windowing {
void JFrame(){
JFrame frames = new JFrame("Total recall");
frames.setSize(1000,8000);
frames.setVisible(true);
frames.pack();
//Buttons push = new Buttons();
//((Buttons) push).buttons();
JTextField wager = new JTextField(1);
wager.setSize(100,200);
wager.setVisible(true);
wager.setLocation(100, 200);
frames.add(wager);
//frames.add(push);
}
}
You could remove the call to frames.pack(); it overrides the previously set frame size.
However, what you really want to do is remove the frames.setSize(1000,8000) and move frames.pack() down to the bottom of the method; that will ensure that the frame is big enough to display its contents but not too big to fit on the screen.
If you call pack before adding anything to the frame (like you are doing now), it will make the window extremely small; it's probably appearing near the upper left of your screen, but you won't notice it unless you know where to look.
It looks like you have a number of "opportunity areas" here.
To start, it seems like you set frame size to 1000x8000 because you didn't see any change right?
Secondly you call setVisible on the textField because you didn't see that either.
And finally you're setting the size of the textfield ( I guess because you're seeing it take the whole frame )
The problem here is that you have to invoke pack and setVisible at the end of the construction. Also, you have to learn how to use layout managers and frames.
Swing, is very powerful, but it is a bit hard to grasp at the beginning.
These two links will be helpful:
How to make frames
Using Layout Managers
I've changed your code and the result looks like this:
Here's the modified source code.
import javax.swing.*;
import java.awt.*;
public class Windowing {
public static void main( String [] args ) {
Windowing windowing = new Windowing();
windowing.showFrame();
}
void showFrame(){
JFrame frame = new JFrame("Total recall");
JButton push = new JButton("Push");
JTextField wager = new JTextField(15);
// Panels do have "FlowLayout"
JPanel panel = new JPanel();
panel.add(wager);
panel.add(push);
frame.add( panel );
frame.pack();
frame.setVisible(true);
}
}
Try to use setPreferredSize(Dimension) instead.
Related
I am trying to learn GUI from a book I just got, but I am having tons of problems (my code is attached). When I launch this app, All I get is a minimum window that need to expand every time, and the only thing it shows is one of my radio buttons. I am obviously doing something wrong here. Can somebody please advise me?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class CarPayment
{
public static void main(String[] args)
{
new CarPaymentCalc();
} // main
} // CarPayment
class CarPaymentCalc extends JFrame
{
private JLabel labelTitle, labelInterest, labelLoan;
private JTextField tfLoan, tfInterest, tfAnswer;
private ButtonGroup bgSelect;
private JRadioButton rbPmts36, rbPmts48, rbPmts60;
private JButton bClear;
public CarPaymentCalc()
{
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null); // Centers the window
setTitle("Car Payments Calculator");
// Labels
labelTitle = new JLabel("Calculate My Car Payment");
labelTitle.setVerticalAlignment(JLabel.TOP);
add(labelTitle, JLabel.CENTER);
labelLoan = new JLabel("Loan Amount");
labelLoan.setLocation(0, 10);
add(labelLoan);
labelInterest = new JLabel("Interest");
labelInterest.setLocation(0, 45);
add(labelInterest);
// Input Fields
tfLoan = new JTextField(20);
tfLoan.setLocation(0, 25);
add(tfLoan);
tfInterest = new JTextField(5);
tfInterest.setLocation(0, 60);
add(tfInterest);
JTextArea tfAnswer = new JTextArea(50,10);
tfAnswer.setLocation(0, 110);
add(tfAnswer);
// Radio buttons
bgSelect = new ButtonGroup();
rbPmts36 = new JRadioButton();
rbPmts36.setText("36 Payments");
rbPmts36.setLocation(0, 80);
bgSelect.add(rbPmts36);
add(rbPmts36);
bgSelect.add(rbPmts48);
rbPmts48.setText("48 Payments");
rbPmts48.setLocation(150, 80);
rbPmts48 = new JRadioButton();
add(rbPmts48);
bgSelect.add(rbPmts60);
rbPmts60.setText("60 Payments");
rbPmts60.setLocation(300, 80);
rbPmts60 = new JRadioButton();
add(rbPmts60);
setLayout(null);
pack();
} // CarPaymentCalc
}
Don't use null layouts. Pixel perfect layouts are an illusion in modern UI design, you have no control over fonts, DPI, rendering pipelines or other factors that will change the way that you components will be rendered on the screen.
Swing was designed to work with layout managers to overcome these issues. If you insist on ignoring these features and work against the API design, be prepared for a lot of headaches and never ending hard work.
By looking at JavaDocs for pack...
Causes this Window to be sized to fit the preferred size and layouts
of its subcomponents. The resulting width and height of the window are
automatically enlarged if either of dimensions is less than the
minimum size as specified by the previous call to the setMinimumSize
method. If the window and/or its owner are not displayable
yet, both of them are made displayable before calculating the
preferred size. The Window is validated after its size is being
calculated.
You will note that pack relies on the layout manager API to determine the preferred viewable size of the frames content. By setting the layout manager to null, you've prevented it from been able to determine this information, so basically, it's done nothing.
If your book is telling you to use null layouts, get rid of it, it's not teaching you good habits or practices.
Take a look at Laying Out Components Within a Container for more details about layout managers and how to use them
Other problems you are having:
Calling setVisible(true); before you've finished building the UI can sometimes prevent the UI from appearing the way you intended it to. You could call revalidate on the frame, but it's simpler to just call setVisible last.
The calculation used by setLocationRelativeTo uses the frames current size, but this hasn't been set yet. Instead, you should do something like:
public CarPaymentCalc() {
//...build UI here with appropriate layout managers...
pack();
setLocationRelativeTo(null);
setVisible(true);
}
I would also discourage you from extending directly from top level containers like JFrame, apart from the fact that you're not adding any functionality to the frame per se, it prevents you from re-using the IU later.
Better to start with a JPanel and add this to whatever you want, but that's just me.
So I would like to have three JButtons all on top of each other, but not to large in width or height either. I am not too familiar with Java's layouts, and to be honest I am not too keen on them. Please view the image a code below to explain to me how, thanks.
package com.aqagame.harrykitchener;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class Main
{
private JButton playGame, playerNames, exitGame;
public Main()
{
JPanel mainCard = new JPanel(new BorderLayout(8, 8));
playGame = new JButton("Play Game");
playerNames = new JButton("Player Names");
exitGame = new JButton("Exit Game");
mainCard.add(playGame, BorderLayout.NORTH);
mainCard.add(playerNames, BorderLayout.CENTER);
mainCard.add(exitGame, BorderLayout.SOUTH);
JFrame window = new JFrame("Harry's AQA game");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.getContentPane().add(mainCard);
window.setSize(900, 800);
window.setLocationRelativeTo(null);
window.setVisible(true);
}
public static void main(String args[])
{
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Main();
}
});
}
}
Check out the Java Documentation for the different layout managers. I know you're not familiar with them, which is why you should probably start. Once you get used to them there is no end to their benefits. There is a lot of excellent information in the documentation and I am sure you will learn a lot. Personally, I recommend looking at the Box Layout:
Create JPanel that uses a GridLayout and add all the buttons to the panel. The GridLayout will automactially size the buttons to be the same size.
Set the layout manager of your main window to use a GridBagLayout.
add the panel to the main window using the default GridBagConststraints. Then the panel will automatically be centered both horizontally and vertically.
To not use Box or GridBag, I think a combination such as this may work out:
Have main panel (let's call it A) have a BorderLayout
Create another panel (let's call it B), with a FlowLayout, with constructor aligning components to the center
Create another panel (let's call it C), with a GridLayout, 1 column 3 rows
Add each button to a new JPanel with a FlowLayout (1 JPanel per button, so buttons are wrapped by a FlowLayout), and then add each of those JPanels to C
Add C to B
Add B to A (center position)
I think this should cause buttons to be on top of each other with small amount of padding while not being stretched widthwise and while appearing in the center of the screen.
Alright I'm relatively new to programming and it may be just something simple that I'm missing but the other threads related to this topic the poster didn't give adequate information relative to their issue for others to provide quality answers so I will give it a shot.
public BenchUI(JFrame j){
jf = j;
init();
add(mainPanel);
topPanelButtons();
selectedCustomer();
rentalOptions();
clientListBox();
}
At this point i can point out that everything works perfectly until I add the clientListBox() method. (below)
public void clientListBox(){
clientList = new JComboBox(moo);
clientList.setPreferredSize(new Dimension(460,30));
gbc.gridx = 0;
gbc.gridy = 0;
leftSide.add(clientList,gbc);
}
i can comment it out and get my whole GUI back working perfectly but without a JComboBox.
moo is String [] moo = {"Fish","Goat", "Monkey"};
a dummy string just for testing purposes and initialized at the start.
So any idea why my GUI completely disappears when I place in the clientList?
If anything else is necessary I'll be watching this thread and can provide additional information.
As a side note I keep getting warnings for "Raw Types" but it works without specifiying, could I potentially run into trouble by not specifying my JComboBox?
EDIT:
ok I believe I've duplicated whatever the issue is in this code
import javax.swing.JFrame;
import javax.swing.*;
import java.awt.*;
public class main {
public static void main(String[] args){
JFrame jf = new JFrame();
jf.setExtendedState(JFrame.MAXIMIZED_BOTH);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setResizable(false);
BenchUI bu = new BenchUI(jf);
jf.add(bu);
}
}
public class BenchUI extends JPanel{
JPanel one;
JFrame jf;
JComboBox<String> clientList;
String[] moo = {"Goat", "Fish", "Donkey"};
public BenchUI(JFrame j){
jf = j;
one = new JPanel(new GridBagLayout());
one.setBackground(Color.blue);
one.setPreferredSize(new Dimension(300,300));
clientList = new JComboBox<String>(moo);
one.add(clientList);
add(one);
}
}
with the clientList stuff commented out I get my silly little blue panel and once it is added I lose the blue panel and the combobox doesnt show up as well...betting on this is a facepalm issue at this point >.<
EDIT: to include the main class.
EDIT: took out the comment marks for the JComboBox constructor and implementer
Your posted sort of sscce-like (not a real SSCCE by the way since we can't run it) code doesn't add any such as the JComboBox to the JPanel and adds no components such as the current JPanel to the JFrame.
public class BenchUI extends JPanel{
JPanel one;
JFrame jf;
JComboBox<String> clientList;
String[] moo = {"Goat", "Fish", "Donkey"};
public BenchUI(JFrame j){
jf = j;
one = new JPanel(new GridBagLayout());
one.setBackground(Color.blue);
one.setPreferredSize(new Dimension(300,300));
//clientList = new JComboBox<String>(moo);
//one.add(clientList);
add(one);
}
}
and so it makes sense that none of the components will show up on any JFrame. You will want to read the Swing tutorials on how to add components to other components (or containers) and how to create and show a JFrame. Have a look at How to Use Swing Components.
Edit
Your latest code now does in fact add the BenchUI JPanel to the JFrame, but still you add no components to the BenchUI JPanel, and in fact you don't even construct your JComboBox but only create a JComboBox variable. Again, I strongly urge you to read the Swing tutorials which I've linked to above as well as the general Java tutorials.
Edit 2
Some general advice:
If you want to add a component to a GUI you must first create the component object. You are declaring your clientList JComboBox, but you never create the object.
Then you must add the component object to a container that eventually will be part of the hierarchy leading to a top level window such as a JFrame, JDialog, JApplet and such. You never add a clientList object to the GUI.
You should add your components to the top level window before calling pack() on the top level window -- which tells all the layout managers to lay out all the components they hold.
You should then call setVisible(true). One problem with your code (other than not creating important components and not adding them to the GUI!) is that you're calling setVisible(true) on your JFrame way too early before adding anything to the GUI.
Read the Swing tutorial, but especially the one on using layout managers and on adding components to a top level window.
Edit 3
OK, now you're creating your JComboBox, but you still are adding all components to your JFrame after setting it visible. Please re-check my 3rd and 4th bullets in the bullet list above.
When I create my GUI I use a cardlayout to hold my different panels as I'm sure many know. This sets my screen to the width and height of my largest panel. This causes problems with the aesthetics of my first to screens, which are much smaller than SudokuPanel and CalkuroPanel.
I have tried setting the preferred size when I change to the larger screens, but to no avail.
Any help with links to good info or anything that will just generally help would be greatly appreciated :).
Please find my main class (where I draw the GUI) below:
import java.awt.*; import javax.swing.*; import java.util.*;
public class puzzleGUI{
private static JPanel screens;
public static String username;
static public void main (String[] args){
JFrame puzzle = new JFrame ("Sudoku/Calkuro Pro");
...
PuzzleStartPanel startPanel = new PuzzleStartPanel();
PuzzleChoosePanel choosePanel = new PuzzleChoosePanel();
PuzzleSudokuPanel sudokuPanel = new PuzzleSudokuPanel();
PuzzleCalkuroPanel calkuroPanel = new PuzzleCalkuroPanel();
screens = new JPanel(new CardLayout());
screens.add(startPanel, "start");
screens.add(choosePanel, "choosePuzzle");
screens.add(sudokuPanel, "sudoku");
screens.add(calkuroPanel, "calkuro");
screens.setPreferredSize (new Dimension(250, 80));
puzzle.setJMenuBar(menuBar);
puzzle.getContentPane().add(screens);
puzzle.pack();
puzzle.setVisible(true);
puzzle.setResizable(false);
puzzle.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
}
static public void getUsername(String str){
username = str;
}
static public void openWindow(String newFrame){
CardLayout cl = (CardLayout)(screens.getLayout());
cl.show(screens, newFrame);
}
}
Edit
brainblast tried to pack the frame after resetting the preferred size when openWindow is called, and wolah, new frame size :D
static public void openWindow(String newFrame, int a, int b){
CardLayout cl = (CardLayout)(screens.getLayout());
cl.show(screens, newFrame);
screens.setPreferredSize (new Dimension(a, b));
puzzle.pack();
}
can i set the size of individual panels in a cardlayout
Certainly. But the layout will ignore them and make every card the same size. The best you can hope for is to add the smaller panels to another panel (with a layout) that allows the content to shrink.
This answer shows this technique using a single label. Swap the label for the 'small panels' and using the layouts on the right, it will be centered.
I had a similar problem and I resolved it by a little cheat ("dirty code").
I had two panels: SmallOne and HugeOne. I set visibility of HugeOne to false. In this case the SmallOne sets the size of whole CardPanel. You can make a method that is called when user selects HugeOne panel and in this method you put HugeOne visibility on true. And CardPanel will resize.
Works like a charm :)
I am trying something very basic:
I have a list of 5 buttons. They are in a FlowLayout and the general idea should be that once I click one it should disappear and the others should reorder themselves accordingly.
Now, if I call setVisible(false) the button becomes invisible, but it still occupies it's space in the Layoutmanager.
Is there any way to keep the Button in the JPanel while hiding it so it doesn't get picked up by Layout?
Update:: Thanks for all the answers, the problem with removing the buttons is that the order is important. The problem I was trying to solve was a find as you type szenario where a very long list of buttons gets filtered down to only the ones matching the characters entered so users can easily click them. Since users can delete characters from the search field ordering is important and buttons have to pop back in once they match again.
Works fine for me.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FlowLayoutInvisible extends JFrame
implements ActionListener
{
JPanel north;
int i;
public FlowLayoutInvisible()
{
north = new JPanel();
for (int i = 0; i < 5; i++)
{
JButton button = new JButton("North - " + i);
button.addActionListener(this);
north.add(button);
}
getContentPane().add(north, BorderLayout.NORTH);
}
public void actionPerformed(ActionEvent e)
{
Component c = (Component)e.getSource();
c.setVisible(false);
((JPanel)c.getParent()).revalidate();
}
public static void main(String[] args)
{
FlowLayoutInvisible frame = new FlowLayoutInvisible();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
If you need more help post your SSCCE.
Update: I don't know if the revalidate() is required. I seemed to have a problem once but now I can't duplicate the problem.
Just remove it:
panel.remove( button );
What's wrong with this option?
Layout managers are thought precisely to avoid having the "user" to make tricks in order to have each component it the right place ( although it seems to provoke the opposite effect )
Removing the button from the panel will have the effect of laying out again all the remaining components. That's why it's name is "Layout manager" it manages to layout the components for you.
I see two possibilities:
Write your own layout manager that listens for changes to its children's visible property - shouldn't be too hard, you can probably subclass FlowLayout to do it.
actually remove the clicked-button from the panel and, if necessary, re-add it later.
You could override each button's getPreferredSize() methods (and possibly getMinimumSize() as well to return 0,0 when the component is invisible; and you need to call, I think, invalidate() (or revalidate or validate, I can never keep them straight) on the container.