I'm making a Game where I have to DrawingComponent painting everything related to the game. Now I want to add a "close" button over the DrawingComponent.
public class SimulationWindow extends JFrame
{
private static final long serialVersionUID = 1L;
public SimulationWindow()
{
super("Game");
setUndecorated(true);
setExtendedState(JFrame.MAXIMIZED_BOTH);
getContentPane().setBackground(Color.BLACK);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton closeButton = new JButton();
closeButton.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent arg0) {
Game.close = true;
}
});
add(new DrawingComponent());
add(closeButton);
setVisible(true);
}
}
But it's just a grey area that pops up. The DrawingComponent which is essentially the game is not visible.
add(new DrawingComponent());
add(closeButton);
You can only add a single component to the BorderLayout.CENTER, which is the default location when you don't specify a constraint.
If you want the button added to the drawing panel the basic code would be:
DrawingComponent draw = new DrawingComponent();
draw.setLayout(...); // set the appropriate layout manager
draw.add( closeButton );
add(draw, BorderLayout.CENTER); // explicitly see the location
Related
I've hit a problem in getting a JPanel to update.
My simple program uses a custom JPanel which displays a label and a textfield. A Jbutton on the main panel is used to replace the JPanel with a new JPanel. The initial panel shows up fine but when the button is pressed the panel is not updated with a new MyPanel. I can tell that a new object is being created as count is being incremented.
public class SwingTest extends JFrame{
private JPanel mp;
private JPanel vp;
private JButton button;
public static void main(String[] args) {
SwingTest st = new SwingTest();
}
public SwingTest() {
vp = new MyPanel();
mp = new JPanel(new BorderLayout());
mp.add(vp, BorderLayout.CENTER);
button = new JButton("Change");
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent ae) {
vp = new MyPanel();
vp.revalidate();
}
});
mp.add(button, BorderLayout.SOUTH);
this.add(mp);
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
setSize(250, 150);
pack();
setVisible(true);
}
}
and my custom panel....
public class MyPanel extends JPanel{
private JLabel label;
private JTextField tf;
static int count = 0;
public MyPanel(){
count++;
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
setPreferredSize(new Dimension(400, 200));
c.gridx = 0;
c.gridy = 0;
label = new JLabel(String.valueOf(count));
tf = new JTextField(10);
add(label,c);
c.gridx = 1;
add(tf, c);
}
}
You state:
A Jbutton on the main panel is used to replace the JPanel with a new JPanel.
And yet this code:
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent ae) {
vp = new MyPanel();
vp.revalidate();
}
});
and yet this code does not do this at all. All it does is change the JPanel referenced by the vp variable, but has absolutely no effect on the JPanel that is being displayed by the GUI, which suggests that you're confusing reference variable with reference or object. To change the JPanel that is displayed, you must do exactly this: add the new JPanel into the container JPanel into the BorderLayout.CENTER (default) position, then call revalidate() and repaint() on the container.
e.g.,
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
// vp = new MyPanel();
// vp.revalidate();
mp.remove(vp); // remove the original MyPanel from the GUI
vp = new MyPanel(); // create a new one
mp.add(vp, BorderLayout.CENTER); // add it to the container
// ask the container to layout and display the new component
mp.revalidate();
mp.repaint();
}
});
Or better still -- use a CardLayout to swap views.
Or better still -- simply clear the value held by the JTextField.
For more on the distinction between reference variable and object, please check out Jon Skeet's answer to this question: What is the difference between a variable, object, and reference?
For some reason the last added button does not get displayed. I tried reordering them but still the same result. I checked the coordinates and they are correct.
The last 3 is where I get the problem. The last "add" button doesn't get displayed.
public class MainScreen extends Frame implements MouseListener{
HowToPlay otherFrame;
Button start, howto, settings, about ;
Image MainMenu;
MainScreen(){
Toolkit tkMM = Toolkit.getDefaultToolkit();
MainMenu = tkMM.getImage(this.getClass().getResource("MainMenu.jpg"));
otherFrame = new HowToPlay();
Button start = new Button ("Start Game");
start.setBounds(98, 333, 326, 51);
Button howto = new Button ("How to Play");
howto.setBounds(98, 389, 326, 29);
howto.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setVisible(false);
otherFrame.setVisible(true);
}
});
Button settings = new Button ("Settings");
settings.setBounds(98, 424, 326, 29);
Button about = new Button ("About");
about.setBounds(98, 462, 326, 29);
about.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setVisible(false);
otherFrame.setVisible(true);
}
});
add(start);
add(howto);
add(settings);
add(about);
setVisible(true);
setSize(500, 500);
setResizable(false);
setLayout(null);
setLocationRelativeTo(null); // Center the frame
setSize(500,500);//size of the canvass
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e){
super.windowClosed(e);
System.exit(0);
}
});
}
Wow nice it worked. Still puzzled by the disappearing button problem though.
The default layout manager is a BorderLayout.
When you add components to a BorderLayout without specifying a constraint the component will be added to the CENTER. However, only one component can be added to the center, so the last one added (the "about" button) will be handled by the layout manager.
When you invoke the setVisible(true) method, the layout manager is invoked and the "about" button is given a size/location. All the other buttons are ignored because the BorderLayout doesn't care about them.
However, the size of the frame is (0, 0) so there is no space to allocate to the "about" button so it is given a height of 0, which effectively means there is nothing to paint.
So when the frame is painted the other 3 buttons a painted properly but not the "about" button.
Change the code to:
setSize(500, 500);
setVisible(true);
and see what happens.
Your problem is that you're calling setLayout(null); at the end after adding all components. To fix this, call it at the beginning:
MainScreen() {
setLayout(null);
Toolkit tkMM = Toolkit.getDefaultToolkit();
//.....
Having said that I strongly urge you to avoid use of null layouts and setBounds
e.g.
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.SwingUtilities;
public class MainScreen2 extends Panel {
private static final int PREF_W = 500;
private static final int PREF_H = 500;
public MainScreen2() {
Panel bottomPanel = new Panel(new GridLayout(0, 1));
bottomPanel.add(new Button("Start Game"));
bottomPanel.add(new Button("How To Play"));
bottomPanel.add(new Button("Settings"));
bottomPanel.add(new Button("About"));
setLayout(new BorderLayout());
add(bottomPanel, BorderLayout.PAGE_END);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
Frame frame = new Frame("MainScreen2");
frame.add(new MainScreen2());
frame.pack();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
super.windowClosed(e);
System.exit(0);
}
});
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
The default layout manager for Frame is BorderLayout. When you use add(item) that item is placed in center, replacing anything that was there.
You need to use a different layout manager
I am trying to create a UI for an imaginary vehicle that has both Automatic and Manual modes. When the user sets the vehicle into one of the modes, it should only display the controls relevant to that mode, and I've accomplished this using a CardLayout.
However, I'd also like to be able to specify the location of the various elements of the layout for each card manually - for a static layout I'd do something along the lines of mainPanel.setLayout(null), but this simply gives a blank window when used on a CardLayout (hence the two commented-out lines in the code below).
How would I achieve both of these things? My current code is below:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class UI extends JFrame implements ActionListener{
public UI() {
initUI();
}
private JPanel cardPanel;
private CardLayout cardLayout = new CardLayout();
public final void initUI() {
cardPanel = new JPanel();
cardPanel.setLayout(cardLayout);
JPanel manualPanel = new JPanel();
getContentPane().add(manualPanel);
//manualPanel.setLayout(null);
cardPanel.add(manualPanel, "manual");
JPanel autoPanel = new JPanel();
//autoPanel.setLayout(null);
cardPanel.add(autoPanel, "auto");
JButton startButton = new JButton("START/STOP");
startButton.setBounds(50, 150, 200, 50);
startButton.addActionListener(new startListener());
manualPanel.add(startButton);
autoPanel.add(startButton);
JButton autoButton = new JButton("SWITCH TO AUTO");
autoButton.setBounds(50, 250, 200, 50);
autoButton.addActionListener(new autoListener());
manualPanel.add(autoButton);
JButton upButton = new JButton("^");
upButton.setBounds(125, 320, 50, 50);
upButton.addActionListener(new returnListener());
manualPanel.add(upButton);
JButton downButton = new JButton("\\/");
downButton.setBounds(125, 380, 50, 50);
downButton.addActionListener(new returnListener());
manualPanel.add(downButton);
JButton ccwButton = new JButton("<-");
ccwButton.setBounds(55, 350, 50, 50);
ccwButton.addActionListener(new returnListener());
manualPanel.add(ccwButton);
JButton cwButton = new JButton("->");
cwButton.setBounds(195, 350, 50, 50);
cwButton.addActionListener(new returnListener());
manualPanel.add(cwButton);
JButton ngzButton = new JButton("SOMETHING ELSE");
ngzButton.setBounds(50, 450, 200, 50);
ngzButton.addActionListener(new returnListener());
manualPanel.add(ngzButton);
JButton manualButton = new JButton("SWITCH TO MANUAL");
manualButton.setBounds(50, 250, 200, 50);
manualButton.addActionListener(new manualListener());
autoPanel.add(manualButton);
JButton returnButton = new JButton("SOMETHING ELSE");
returnButton.setBounds(50, 350, 200, 50);
returnButton.addActionListener(new returnListener());
autoPanel.add(returnButton);
setTitle("UI");
setSize(800, 600);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
add(cardPanel, BorderLayout.NORTH);
}
public static void main(String[] args) {
UI ui = new UI();
ui.setVisible(true);
}
public void actionPerformed(ActionEvent e){
}
private class returnListener implements ActionListener {
public void actionPerformed (ActionEvent event) {
}
}
private class autoListener implements ActionListener {
public void actionPerformed (ActionEvent event) {
cardLayout.show(cardPanel, "auto");
}
}
private class startListener implements ActionListener {
public void actionPerformed (ActionEvent event) {
}
}
private class manualListener implements ActionListener {
public void actionPerformed (ActionEvent event) {
cardLayout.show(cardPanel, "manual");
}
}
}
In your example, you create a startButton, but you then attempt to add the same instance to two different panels. Because a component can only occupy one container, you'll need to create two buttons, one for each panel.
As an aside, instead of using a null layout, give each panel BorderLayout, add the buttons to a JPanel having the default FlowLayout, and add the button panel to the SOUTH. You can then nest your illustrations in the CENTER using whatever layout is appropriate.
Addendum: As #Frakcool comments, using a layout will improve the cross-platform appearance of your buttons. Invoke pack() on the enclosing window, and override getPreferredSize() on the nested illustration panel to give it the needed size. In this related example, the CENTER panel is used for drawing only; having no components, its layout then becomes irrelevant.
I'm building a Swing program and I want to be able to use a button to change certain features (Font, ForeGround Color, BackGround Color, etc.) of JComponents (JLabel, JButton).
I can do this without a problem if the components have all been explicitly declared and defined, but I cannot figure out how to do it if they are implicitly built using generic methods.
Below is the gist of what I have so far, minus some unimportant details. When styleButton1 and 2 are clicked, I want to refresh or rebuild the JFrame such that the new values for features/style (in this example, Font) are used for the components (testButton1 and 2), by changing currentFont and then repainting.
I'm not getting any errors with this, but frame and components are not being rebuilt/refreshed, i.e., nothing happens when the style buttons are clicked.
Any ideas on how to make this work? Or any other approaches I can use to get the desired effect?
//imports
public class GuiTesting extends JFrame {
public static void main(String[] args) {
frame = new GuiTesting();
frame.setVisible(true);
}
static JFrame frame;
static Font standardFont = new Font("Arial", Font.BOLD, 10);
static Font secondFont = new Font("Times New Roman", Font.PLAIN, 10);
static Font currentFont = standardFont;
public GuiTesting() {
setTitle("GUI Testing");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 400);
JPanel mainPanel = new JPanel();
getContentPane().add(mainPanel);
mainPanel.add(basicButton("Button1"));
mainPanel.add(basicButton("Button2"));
mainPanel.add(style1Button("Style 1"));
mainPanel.add(style2Button("Style 2"));
}
public static JButton basicButton(String title) {
JButton button = new JButton(title);
button.setPreferredSize(new Dimension(80, 30));
button.setFont(currentFont);
return button;
}
public static JButton style1Button(String title) {
JButton button = new JButton(title);
button.setPreferredSize(new Dimension(80, 30));
button.setFont(standardFont);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
currentFont = standardFont;
frame.repaint();
}
});
return button;
}
public static JButton style2Button(String title) {
JButton button = new JButton(title);
button.setPreferredSize(new Dimension(80, 30));
button.setFont(secondFont);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
currentFont = secondFont;
frame.repaint();
}
});
return button;
}
}
You can store components, which need to refresh style in a list :
private static List<JComponent> components = new ArrayList<JComponent>();
add then in your basicButton() method add new component to refreshing components:components.add(button);
And then in ActionListener you can execute next lines for refreshing style:
for(JComponent c : components){
c.setFont(currentFont);
}
Or you can pass components directly to ActionListener like next :
JButton b1;
JButton b2;
mainPanel.add(b1 = basicButton("Button1"));
mainPanel.add(b2 = basicButton("Button2"));
mainPanel.add(style1Button("Style 1",b1,b2));
and style1Button() code:
public static JButton style1Button(String title,final JComponent... components) {
JButton button = new JButton(title);
button.setPreferredSize(new Dimension(80, 30));
button.setFont(standardFont);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
currentFont = standardFont;
for(JComponent c : components){
c.setFont(currentFont);
}
frame.repaint();
}
});
return button;
}
Create a styleOne method in your JComponent class that sets all of the values you need. It will have access to all fields of your class. Inside the action listener call this method.
Also, don't create your buttons statically like that. Create them within the constructor directly. If you want to override the look of the buttons do it within an init method or constructor. Or, better yet, subclass JButton.
I use this code to set a picture to jframe .
But , now my Jtable don't show, why?
public class samplepage extends JFrame{
private AllUser userModel;
private JTable uTable;
JButton addUser;
JButton deleteUser;
JButton mainButton;
JTextField tf1;
JButton searchButton;
JLabel resultLbl;
public samplepage(){
userModel=new AllUser();
uTable=new JTable(userModel);
add(new JScrollPane(uTable), BorderLayout.CENTER);
add(buttonPanels() , BorderLayout.PAGE_START);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(800,600);
this.setLocation(300, 60);
this.setResizable(false);
}
public final JPanel buttonPanels(){
JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
setPic(this);
addUser=new JButton("Add New User");
deleteUser=new JButton("delete User");
mainButton= new JButton("Main Page");
tf1 = new JTextField(" ");
searchButton=new JButton("Search");
resultLbl=new JLabel();
buttonsPanel.add(addUser);
buttonsPanel.add(deleteUser);
buttonsPanel.add(mainButton);
buttonsPanel.add(tf1);
buttonsPanel.add(searchButton);
buttonsPanel.add(resultLbl);
return buttonsPanel;
}
public void setPic(JFrame jframe){
try{
File f=new File("pics\\user_group.png");
BufferedImage img=ImageIO.read(f);
jframe.setContentPane(new SetMyImage(img));
}
catch(IOException ioe){
}
}
public static void main(String[] args){
new samplepage().setVisible(true);
}
}
second Class:
public class SetMyImage extends JPanel{
private Image img;
public SetMyImage(Image img){
this.img=img;
}
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(img, 00, 00, null);
}
}
Where is my mistake?
uTable=new JTable(userModel);
add(new JScrollPane(uTable), BorderLayout.CENTER);
add(buttonPanels() , BorderLayout.PAGE_START);
First you add the table to the content pane. Then you create your buttonPanels() which invokes the setPic(...) method which creates your image panel and makes it the content pane of your frame so you lose the table.
Remove the setPic() code from your buttonPanels code. Instead your code should be something like:
setPic(...);
uTable=new JTable(userModel);
add(new JScrollPane(uTable), BorderLayout.CENTER);
add(buttonPanels() , BorderLayout.PAGE_START);
Also, you need to set the layout of your image panel to be a BorderLayout.
Since you are painting your image at its actual size there is no need to create a custom panel to do the painting. Instead you can just use a JLabel as your content pane. For more information on this approach see Background Panel.