I've just started learning Swing/JFrame, basically making a GUI.
I've been doing Java for a month now, just using the console, making a sin/true or false games and it is pretty easy for me now.
I decided to take a further step, and I must say it's totally a pain, different logic.
That's what I've done so far:
Main.java:
import java.awt.*;
import javax.swing.*;
import java.io.*;
class Main {
public static void main(String[] args) {
final Gui gui = new Gui();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
gui.createMyGui();
}
});
}
}
gui.java
class Gui {
protected JFrame j = new JFrame("My First window");
protected JPanel p = new JPanel();
protected Container c;
public Gui() {
j.setSize(500, 400);
p.setSize(j.getSize());
this.c = j.getContentPane();
}
public void createMyGui() {
setButtons();
setGuiBackground();
j.setVisible(true);
p.setVisible(true);
this.c.add(p);
}
private void setGuiBackground() {
this.c.setBackground(Color.green);
}
private void setButtons() {
p.add(new JButton("Hey"));
}
}
Problem
I can't really get the button to show up, people are telling me to use setBounds but I am not really sure on how to start as I can't even place a button there. I've tried searching about my problem, but no luck actually.
Basically what happens is a 500x400 green GUI opens, and that's it.
Why won't the button show?
people are telling me to use setBounds
Dont! Layout managers are the correct way to go.
Your problem is you add your buttons to the "p" panel, but you never add it (p panel) to the contentPane
Related
my question is: how do I get the object of my CustomPanel, so that I am able to access its fields (because in my real programm I have some more fields in there) and also am able to delete it from my ArrayList?
I don't know how I have to implement an ActionListener in the Class Window, to somehow get the Object in my Arraylist, which containes the button that got pressed.
Also I am wondering if I am somehow able to implement an ActionListener in the Class CustomPanel which can influence the behaviour of the Object which is an instance of my Class Window.
I have kind of the following code:
public class Window extends JFrame{
ArrayList<CustomPanel> aLCustomPanel = new ArrayList();
JPanel jp = new JPanel();
public Window() {
for(int i=0;i<5;i++){
aLCustomPanel.add(new CustomPanel());
//here I could put the code from the 1 edit - see below
jp.add(aLCustomPanel.get(i));
}
this.add(jp);
}
public static void main(String args[]){
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Window().setVisible(true);
}
});
}
}
class CustomPanel extends JPanel {
private JButton button;
public CustomPanel(){
button = new JButton("button");
this.add(button);
}
public JButton getButton(){
return this.button;
}
}
my Code is much longer and weirder, so I tried to extract the (for this question) importing things.
Thanks for any help in advance!
edit:
for example: I would like to delete the object from the ArrayList, of which the button got pressed.
//imagine this comment in above code
aLCustomPanel.get(aLCustomPanel.size()-1).getButton().addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
button_IwantToDeleteYou(e); //here I want to remove the panel, containing the button that got pressed from the above ArrayList, which is located in Class Window
}
});
edit2:
added a missing bracket and fixed some mistakes, code should be ok now.
Your code contained a few "gaps", i.e. missing code, which I filled in, as follows:
Added calls to [JFrame] methods setDefaultCloseOperation() and pack() and setLocationByPlatform(). I suggest you refer to the javadoc for those methods in order to understand what they do.
I set a layout manager for jp class member variable in your Window class.
Yes, you need to register an ActionListener with the JButton in class CustomPanel and that listener should reside in your Window class - the one that extends JFrame.
Here is my rewrite of your code. Note that I changed the name of class Window to CusPanel so as to distinguish between your class and java.awt.Window class. Not that it makes a difference, I just prefer not to use names of classes from the JDK.
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class CusPanel extends JFrame implements ActionListener {
private static final int COUNT = 5;
private ArrayList<CustomPanel> aLCustomPanel = new ArrayList<>();
private JPanel jp = new JPanel(new GridLayout(0, COUNT));
public CusPanel() {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
for (int i = 0; i < COUNT; i++) {
aLCustomPanel.add(new CustomPanel(this));
// here I could put the code from the 1 edit - see below
jp.add(aLCustomPanel.get(i));
}
this.add(jp);
pack();
setLocationByPlatform(true);
}
public void actionPerformed(ActionEvent actionEvent) {
Object source = actionEvent.getSource();
if (source instanceof JButton) {
JButton button = (JButton) source;
Container parent = button.getParent();
jp.remove(parent);
jp.invalidate();
jp.repaint();
pack();
// aLCustomPanel.remove(parent); <- optional
}
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new CusPanel().setVisible(true);
}
});
}
}
class CustomPanel extends JPanel {
private JButton button;
public CustomPanel(ActionListener parent) {
button = new JButton("button");
button.addActionListener(parent);
this.add(button);
}
public JButton getButton() {
return this.button;
}
}
Note that after removing a CustomPanel, the GUI components need to be laid out again and the JFrame should also be resized accordingly. Hence in the actionPerformed() method, I call invalidate(), then repaint() and then pack(). I also think that if you remove a CustomPanel from the GUI, you should also remove it from the ArrayList, but hey, I still don't understand why you want to do this although I obviously don't know the whole story behind you wanting to do this in the first place.
Of-course, since each button (and each CustomPanel) looks exactly the same, you can't really know which button was removed. Again, I assume you see the big picture whereas I don't.
I'm making a program that has a popup menu with two buttons, one of which should close the popup menu, but I have no idea how to do that and googling hasn't gone too well.
I've tried using popup.hide() but then the menu wouldn't come back, despite doing so when I tried just moving the popup. It also required me to put a SuppressWarning in that case and it took a few seconds for it to close at all. Is there any better way of doing it?
I'm not sure what kind of code is relevant, but here's the relevant buttons and their roles in this(I skipped all the creating the GUI parts that didn't seem relevant, everything looks good and I know that the buttons are working):
package test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
interface CustomButton {
JButton create();
void react(JPopupMenu popup, JFrame frame);
}
class ErrandsButton implements CustomButton {
private JButton errands = new JButton("Errands");
public JButton create() {
return errands;
}
public void react(JPopupMenu popup, JFrame frame) {
errands.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
popup.show(frame, 120, 65);
}
});
}
}
class Test {
static JFrame frame = new JFrame("List");
static CustomButton errands = new ErrandsButton();
static JButton cancelTask = new JButton("Cancel");
static JPopupMenu popup = new JPopupMenu();
static void cancelTask() {
cancelTask.addActionListener(new ActionListener() {
#SuppressWarnings("deprecation")
public void actionPerformed(ActionEvent e) {
popup.hide();
}
});
}
public static void main(String args[]) {
createInterface();
cancelTask();
errands.react(popup, frame);
}
static void createInterface() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
JPanel popup1 = new JPanel();
JPanel button = new JPanel();
popup1.add(cancelTask);
popup.add(popup1);
frame.add(popup);
button.add(errands.create());
frame.getContentPane().add(BorderLayout.CENTER, button);
frame.setVisible(true);
}
}
Use popup.setVisible(true) and popup.setVisible(false).
frame.add(popup); is the problem. Do not add a JPopupMenu to a Container. Instead, use setComponentPopupMenu.
Alternatively, you could do the work yourself by adding a MouseListener whose mousePressed, mouseReleased and mouseClicked methods call isPopupTrigger and show. (It is vital that you do this in all three of those methods—different platforms have different conditions for showing popup menus.)
But really, using setComponentPopupMenu is easier.
i make simple game , and it consist of 2 files , first file is "Alibaba.java" which is extended from JFrame , i used it to display general contents of the game !,
and the second file is "intro.java" which is extended from JPanel , i used it to show intro of the game which include (title & background & person) ,
my problem occured when i tried to add a simple button in the intro ! , i did a function to create the button , but the problem is when i run the game , the button which i added it don't appear !! , but when i tried add it from the first file which extended from JFrame , its appeared ! ,
so what is the problem in my code ? is JPanel don't accept JButtons ! or i must create the buttons from the JFrame file ?!
so i need to know how to add Jbutton inside Jpanel instead of add Jbutton in JFrame Direct !!,
this is my samples of my codes which contain the problem :
1st file (Alibaba.java)
package alibaba;
import java.awt.Color;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Toolkit;
import javax.swing.JFrame;
public class Alibaba extends JFrame {
public Alibaba(){
super("Alibaba");
Intro intro = new Intro();
this.add(intro);
GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice device = environment.getDefaultScreenDevice();
device.setFullScreenWindow(this);
}
public static void main(String[] args) {
Alibaba alibaba = new Alibaba();
}
}
2nd file(Intro.java) :
package alibaba;
import javax.swing.JButton;
public class Intro extends javax.swing.JPanel implements Runnable{
Thread _intro_run;
public Intro() {
_intro_run = new Thread(this);
_intro_run.start();
}
#Override
public void run() {
// Here i tried to add a button to the Intro !!!
this.add(this.createbutton("Exit"));
}
public JButton createbutton(String text){
JButton _button = new JButton(text);
return _button;
}
}
So please tell me what is the problem and how to solve it , sorry but iam new to java , new to programming games world ! ,, thank you :)
You have to add the JButton inside the main thread, cross thread Component manipulation is bad.
For example:
public Intro() {
JButton exitButton = new JButton("Exit");
this.add(exitButton);
}
Alternatively, use SwingUtilities.invokeLater(Runnable). For example, in your run method:
#Override
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
add(createbutton("Exit"));
}
}
}
Based on discussion it seems that you are overriding the paint or paintComponent methods. You need to call super in them, like:
void paint(Graphics g) {
super.paint(g);
// do other stuff to g
}
In addition, it is a bad sign that you have a JPanel that implements Runnable. In Java, all UI work (here you are using Swing components) is done from the Event Dispatching Thread - having an actual Swing component (your Intro class is a JPanel) Runnable flies in the face of that.
Suggestions:
Anytime you add a new component to a container, you have to tell the layout managers to layout the new and existing components. This is done by calling revalidate() on the JPanel receiving the button. You also should call repaint() on the JPanel after this.
You shouldn't do any of this in a background thread.
Most important read the Swing tutorials as they will tell you all of this and more.
I made a game that is based in a jpanel. When I add the jpanel to a jframe, it works fine on both pc's and macs.
here is the class where I add the jpanel to the jframe:
import javax.swing.JFrame;
public class Start{
public static void main(String[] args){
JFrame f = new JFrame("Rocks");
f.setSize(600,500);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Board b = new Board();
f.add(b);
f.setVisible(true);
}
}
However, when I add this jpanel to a japplet, it still works perfectly on pc's, but not on macs. In the eclipse applet tester, the first screen paints, but it doesn't accept keyboard input to start the game. In any browser/html page though, the game doesn't seem to load at all, and when I open the java console of chrome I see no errors.
here is the class where I add the jpanel to the japplet
import javax.swing.JApplet;
public class rockAppletStart extends JApplet{
public void init(){
Board b;
b = new Board();
add(b);
b.focus();
}
public void start(){}
public void stop(){}
public void destroy(){}
}
I would appreciate any help that could be offered, and I'm willing to provide more information if necessary. I could even provide the other classes of the game, but there very long and messy, and I'd rather not unless necessary.
The applet version of the game can be found here at gamejolt.com, if you feel like testing it out. If you have a pc, it should work fine, but with a mac it won't.
** edit **
here you can download the .jar file of all the classes and resources. Feel free to use the files to test out your solution yourself if you want... Otherwise, Ill have access to a mac on Tuesday and I will test all solutions then.
http://dl.dropbox.com/u/18832480/Rocks_Source_file.jar
This is just a SWAG, but since Swing threading issues can often cause pernicious, unpredictable and hard to detect errors, what if you create your applet in a thread-safe manner? i.e.,
public void init() {
try {
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGUI();
}
});
} catch (Exception e) {
System.err.println("createGUI didn't successfully complete");
}
}
private void createGUI() {
Board b;
b = new Board();
getContentPane().add(b);
b.focus()
}
The JApplet is stealing the focus from the Board. To prevent it, add the following to the end of your init() method:
setFocusable(false);
I would like to create a JFrame with two specifal features:
JFrame should not grab focus while maximized from minimized state.
When a JFrame created or became maximized from minimized state, it should flash in the Windows bar until a user will grant a focus to it. (like as in ICQ clients ).
Does anybody know how the second requirement can be implemented?
Little self-explained example:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class JFrameTest {
private static JFrame childFrame;
public static Container getParentContentPane() {
JPanel panel = new JPanel();
JButton button = new JButton("Create\\Restore child frame");
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
createOrRestoreChildFrame();
}
});
panel.add(button);
return panel;
}
private static void createOrRestoreChildFrame() {
if (childFrame == null) {
childFrame = new JFrame("Child Frame");
childFrame.setLocation(200, 200);
childFrame.add(new JLabel("Child Frame"));
childFrame.pack();
setChildFrameVisible();
} else {
setChildFrameVisible();
}
}
private static void setChildFrameVisible() {
childFrame.setFocusableWindowState(false);
childFrame.setVisible(true);
flashInWindowsBar(childFrame);
childFrame.toFront();
childFrame.setFocusableWindowState(true);
}
/**
* Should Make child frame flash in Windows bar.
* Currently, it does not work for me.
* Could anybody help me to fix this please? )
*/
private static void flashInWindowsBar(JFrame childFrame) {
childFrame.setState(JFrame.ICONIFIED);
childFrame.toFront();
}
private static void createAndShowGUI() {
JFrame parentFrame = new JFrame("JFrame Demo");
parentFrame.setLocation(100, 100);
parentFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
parentFrame.setContentPane(getParentContentPane());
parentFrame.pack();
parentFrame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Thanks!
The following code worked for me exactly as you described:
f.setState(JFrame.ICONIFIED);
f.toFront();
f is a JFrame.
Unfortunately, this isn't something that you can do natively under any Java platform. Anyone who manages to get it working by using the kind of 'trickery' that you've shown, will be disappointed to find that it is unlikely to work on another version of Windows, or even another computer with the same version of Windows. The only times I've ever seen a Java window flash is due to some glitch in Swing when minimizing all windows to the taskbar.
As this article on making Java applications feel native shows, it's the same on Mac OS.
Your best bet is to use the techniques described in the above article to make a JNI which does the Windows API call, or get a license for JNIWrapper (search for it) which does it all for you (best option if you are making a commercial app, or making it for a client who is willing to pay for such a feature). It looks like you can get a 30-day trial for that.
The only other thing I could suggest is create a poor-man's equivalent of a pop-up notification system. When you want to alert the user, create a Frame without a border, put it in the bottom-right corner of the screen, make it non-focusable and show it for a brief period of time.
The JPanel does not flash. Try it instead of JFrame.