JPanels, JFrames, and Windows, Oh my! - java

Simply stated, I am trying to make a game I am working on full-screen.
I have the following code I am trying to use:
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice gs = ge.getDefaultScreenDevice();
if(!gs.isFullScreenSupported()) {
System.out.println("full-screen not supported");
}
Frame frame = new Frame(gs.getDefaultConfiguration());
Window win = new Window(frame);
try {
// Enter full-screen mode
gs.setFullScreenWindow(win);
win.validate();
}
Problem with this is that I am working within a class that extends JPanel, and while I have a variable of type Frame, I have none of type Window within the class.
My understanding of JPanel is that it is a Window of sorts, but I cannot pass 'this' into gs.setFullScreenWindow(Window win)... How should I go about doing this?
Is there any easy way of calling that, or a similar method, using a JPanel?
Is there a way I can get something of type Window from my JPanel?
-
EDIT: The following method changes the state of JFrame and is called every 10ms:
public void paintScreen()
{
Graphics g;
try{
g = this.getGraphics(); //get Panel's graphic context
if(g == null)
{
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setExtendedState(frame.getExtendedState()|JFrame.MAXIMIZED_BOTH);
frame.add(this);
frame.pack();
frame.setResizable(false);
frame.setTitle("Game Window");
frame.setVisible(true);
}
if((g != null) && (dbImage != null))
{
g.drawImage(dbImage, 0, 0, null);
}
Toolkit.getDefaultToolkit().sync(); //sync the display on some systems
g.dispose();
}
catch (Exception e)
{
if(blockError)
{
blockError = false;
}
else
{
System.out.println("Graphics context error: " + e);
}
}
}
I anticipate that there may be a few redundancies or unnecessary calls after the if(g==null) statement (all the frame.somethingOrOther()s), any cleanup advice would be appreciated...
Also, the block error is what it seems. I am ignoring an error. The error only occurs once, and this works fine when setup to ignore the first instance of the error... For anyone interested I can post additional info there if anyone wants to see if that block can be removed, but i'm not concerned... I might look into it later.

Have you made any progress on this problem? It might be helpful if you could update your question with your expected behavior and what the code is actually doing? As was already pointed out, JFrame is a subclass of Window, so if you have a JFrame, you don't need a Window.
For what it's worth, I have a Java app which works in fullscreen mode. Although the screen is not repainted as often as yours, it is repainted regularly. I do the following to enter fullscreen:
// pseudo-code; not compilable
JPanel container = new JPanel();
container.setOpaque( true ); // make sure the container will be visible
JFrame frame = new JFrame();
frame.getContentPane().add(container); // add the container to the frame
frame. ... //other initialization stuff, like default close operation, maximize, etc
if ( fullScreenModeIsSupported )
frame.setUndecorated( true ); // remove window decorations from the frame
gs.setFullScreenWindow( frame );
frame.validate();
Then whenever I need to update the screen, I just plug a new JPanel into the container JPanel:
// pseudo-code; not compilable
container.removeAll(); // clean out the container
container.add( jPanelWithNewDisplay ); // add the new display components to the container
container.validate(); // update and redisplay
container.repaint();
Can't claim that it's technically perfect, but it works well for me. If the pseudo-code examples don't cut it, I can spend some time putting together a compilable example.

JPanel is not a subclass of Window. JFrame is.
So you could try:
JFrame yourFrame = new JFrame();
yourFrame.add(yourPanel);
appyYourFullScreenCodeFor( yourFrame );
That should work.

I think I got what you need.
Set the frame undecorated, so it
comes without any title bar and
stuff.
Add your panel to the frame., so it
looks like only your panel is shown.
Maximize your frame. So now it
should look like there's only your
panel taking the full screen without
and window stuff.
frame.setUndecorated(true);
frame.add(panel); //now maximize your
frame.
Note: Its important to note that the undecorated API can only be called when your frame is undisplayable, so if its already show, then first you need to do setVisible(false).
EDIT1: If all you want is to get the window containing your panel, then you can do this:
Window win = SwingUtilities.getAncestorOfClass(Window.class, myPanel);
Once you get the window instance you can pass it wherever you want.
EDIT2: Also the Frame class extends Window so you can directly do gs.setFullScreen(frame). You dont need to create a new window for that frame.

My understanding of JPanel is that it
is a Window of sorts
Why would you think that? Did you read the API? Does JPanel extend from Window?
You can try using the SwingUtilities class. It has a method that returns the Window for a given component.

Related

java GUI multiple buttons output display error?

I am beginner in Java. This is my first project.
The GUI of the code keeps changing every time I run the code.
Sometimes output doesn't even load completely.
This is the code for just initializing a chess board 8X8 jbuttons.
I have put down the images do checkout the hyperlinks below.
Is there any solution that shows the same output every time the code executes?
package chess;
import game.*;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.util.*;
public class board{
static JButton [][] spots =new JButton [8][8];
public static void main(String[] args){
board b =new board();
b.initializeboard(spots);
}
public void initializeboard(JButton [][] spots){
JFrame f = new JFrame("CHESS");
f.setVisible(true);
f.setSize(800,800);
GridLayout layout =new GridLayout(8,8,1,1);
f.setLayout(layout);
for(int ver=0;ver<8;ver++){
for(int hor=0;hor<8;hor++){
JButton button = new JButton();
if((ver+hor)%2==0){
button.setBackground(Color.WHITE); }
else{
button.setBackground(new Color(255,205,51)); }
pieces p =new pieces();
spots[ver][hor] = button;
p.setButton(button);
f.add(button);
}
}
} //initialize board
} // close board
Improper Execution
Correct Execution
Incomplete Execution
I am beginner in Java.
First of all, class names SHOULD start with an upper case character. Have you even seen a class in the JDK that does not start with an upper case character? Learn by example from the code in your text book or tutorial.
Is there any solution that shows the same output every time the code executes?
All components should be added to the frame BEFORE the frame is made visible.
When the frame is made visible the layout manager is invoked and the components are given a size/location. If you add components to a visible panel, then you need to invoke revalidate() and repaint() on the panel to make sure the layout manager is invoked.
Must admit I'm not sure why you get this random behaviour. Some components are getting a size/location and other are not even though the layout manager is not invoked.
I would suggest you restructure your code something like:
JPanel chessboard = new JPanel( new GridLayout(8, 8, 1, 1) );
// add buttons to the panel
JFrame frame = new JFrame("CHESS")
frame.add(chessboard, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
Other comments:
Don't set the size of the frame. Using 800 x 800 will not make each button 100 x 100. The frame size also include the title bar and borders, so each button size will be less than you expect.
Instead you can create a variable outside of your loops:
Dimension buttonSize = new Dimension(100, 100)
Then when you create the button you use:
button.setPreferredSize( buttonSize );
Now when pack() method is invoked is will size the frame at the preferred size of all the components added to the frame.
All Swing components should be create on the Event Dispatch Thread (EDT). Read the section from the Swing tutorial How to Make Frames. The FrameDemo.java code shows you one way to structure your class so that the invokeLater(…) method is used to make sure code executes on the EDT.
Don't make your variables static. This indicates incorrect class design. Check out the MenuLook.java example found in How to Use Menus for a slightly different design where your ChessBoard becomes a component created in another class. You can then define your instance variables in that class.

JPanel inside JFrame doesn't show content sometimes. Why?

I managed to fix it but I don't understand why the same code results in different results. Some classmates have had the same problem.
The issue is that it I use miVentana.setVisible(true); before chicha(); the elements inside the JPanel will show when executing but if I run it again sometimes they won't ve visible until I resize the window, a few times not even the JPanel background color was visible. Just clicking the "Run" bottom on the IDE without changing anything else.
I just tried it 10 consecutive times and the elements were only visible on the 4th attempt.
Could this come from some memory garbage remaining from previous executions of the code?
I'm using Eclipse Version: Photon Release (4.8.0).
This is the code with the weird behaviour:
public class Ej10 extends JFrame {
public Ej10() {
setLayout(null);
}
static Ej10 miVentana = new Ej10();
public static void main(String[] args) {
miVentana.setTitle("Ejercicio10");
miVentana.setBounds(20, 20, 500, 600);
miVentana.setLocationRelativeTo(null);
miVentana.setVisible(true);
chicha();
//miVentana.setVisible(true);
}
static void chicha() {
JPanel miPanel = new JPanel();
miPanel.setLayout(new BoxLayout(miPanel, BoxLayout.PAGE_AXIS));
miPanel.setBounds(20, 20, 350, 450);
miPanel.setBackground(Color.CYAN);
JLabel lUsuario = new JLabel("Usuario:");
lUsuario.setVisible(true);
JTextField campoUsuario = new JTextField();
JLabel lPwd = new JLabel("Contraseña:");
JPasswordField campoPwd = new JPasswordField();
JButton bAcceso = new JButton("Acceder");
miPanel.add(lUsuario);
miPanel.add(campoUsuario);
miPanel.add(lPwd);
miPanel.add(campoPwd);
miPanel.add(bAcceso);
miPanel.setVisible(true);
miVentana.add(miPanel);
}
}
Components need to be added to the frame BEFORE the frame is made visible.
One of the functions of the setVisible() method is to invoke the layout manager. Otherwise components have a size() of (0, 0) so there is nothing to paint.
Also, all GUI components should be created on the Event Dispatch Thread (EDT), otherwise you can have random results. Read the section from the Swing tutorial on Concurrency for more information.
Take a look at the FrameDemo from How to Make Frames for the most basic example of how your code should be structured to avoid problems. It shows how to create components on the EDT and how to make the frame visible.
they won't ve visible until I resize the window,
Resizing the frame will also cause the layout manager to be invoked.
miPanel.setBounds(20, 20, 350, 450);
That statement will do nothing because the layout manager of the frame will determine the size and location of the panel based on the rules of the layout manager. The default layout manager for a frame is a BorderLayout, so basically the panel will get all the space available to the frame.
The tutorial also has a section on Layout Managers that you should read.

setLocationRelativeTo() a component, and then shifting it slightly

I'm trying to position a JDialog relative to a JButton in an internal JPanel- which I can do using dialog.setLocationRelativeTo(button), but the dialog then covers the button. I've been trying, quite unsuccessfully, to then move the dialog slightly out of the way.
I've found a few different approaches that seemed promising, to then only produce exactly the same result, from just using setLocation(x,y) after setting the relative location (which seem to override each other), to getting the location of the button from the screen.
I'm warey of being spoonfed this sort of stuff, and having asked a few questions over the last few days, but does anyone have any hints at all, like where I should be looking in the API? Should I be looking at converting the coordinates relative to the component to a screen coordinate? That's my next best guess...but I'm not going to lie, it's definitely confusing me.
You don't need to convert yourself, thanks to Component.getLocationOnScreen():
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
final JFrame f = new JFrame("test");
final JButton b = new JButton("Hello");
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(b, BorderLayout.NORTH);
f.setSize(300, 200);
f.setVisible(true);
b.addActionListener((e) -> {
JDialog dialog = new JDialog(f);
dialog.getContentPane().add(new JLabel(new Date().toString()));
dialog.pack();
Point point = b.getLocationOnScreen();
//dialog.setLocationRelativeTo(b); // Shows over button, as doc says
dialog.setLocation(new Point(point.x, point.y + b.getHeight()));
dialog.setVisible(true);
});
});
}
Works for me...
Doc for Window.setLocationRelativeTo(...) says:
If the component is not null and is shown on the screen, then the
window is located in such a way that the center of the window
coincides with the center of the component.
So the behavior you get is normal.
(Hope I have correctly understood your issue)

visualizing JPanel change within a loop

I am new to Java swing programming. I want to make a frame which will appear red and blue in turn one after another. So, I took 2 child JPanel, 1 for red and other for blue, and a for-loop. On each iteration I remove one panel from parent panel and add another. But, when I run the program it only shows the last state of the frame.
Can anyone explain why? And what's the intended approach to make a program work like that?
My code:
public class Test2 extends JFrame {
public Test2() {
JPanel Red = new JPanel(new BorderLayout());
JPanel Blue = new JPanel(new BorderLayout());
//...initialize Red and Blue
Red.setBackground(Color.red);
Blue.setBackground(Color.blue);
Red.setPreferredSize(new Dimension(200,200));
Blue.setPreferredSize(new Dimension(200,200));
JPanel panel = new JPanel(new BorderLayout());
panel.setPreferredSize(new Dimension(200,200));
add(panel);
pack();
setTitle("Border Example");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
int M = 1000000; //note that, I made a long iteration to not finish the program fast and visualize the effect
for(int i=0;i<M;i++)
{
if(i%(M/10)==0) System.out.println(i); //to detect whether the program is running
if(i%2==0)
{
panel.removeAll();
panel.repaint();
panel.revalidate();
panel.add(Red,BorderLayout.CENTER);
}
else
{
panel.removeAll();
panel.repaint();
panel.revalidate();
panel.add(Blue,BorderLayout.CENTER);
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Test2 ex = new Test2();
ex.setVisible(true);
}
});
}}
Don't use a loop. Swing will only repaint the frame once the entire loop has finished executing.
Instead you need to use a Swing Timer. When the Timer fires you invoke your logic. Read the section from the Swing tutorial on How to Use Swing Timers.
Here is a simple example of a Timer that simply displays the time every second: Update a Label with a Swing Timer
Also, don't remove/add panels. Instead you can use a Card Layout and sway the visible panel. Again read the tutorial on How to Use CardLayout.
Basically you don't need to use a while (or any other) loop, Swing only paints once it has finished that loop then repaint the GUI.
As stated before by #camickr on his answer, you could try a Swing Timer; here's an example that does exactly what you want.
From your comment on another answer:
Could you please explain why "repaint" does not work in a loop? And why is the Timer working without a "repaint"?
Swing is smart enough to know it doesn't needs to repaint in a loop, instead it will repaint once it the loop finishes, if you read the tutorial on Swing Custom Paint on the step 3 it says:
"Swing is smart enough to take that information and repaint those sections of the screen all in one single paint operation. In other words, Swing will not repaint the component twice in a row, even if that is what the code appears to be doing."
And Timer will repaint it, because it's not running on the EDT but in it's own Thread
I would suggest to take in one step at a time.
First make it run without changing panels / colors.
Now it doesn't because this
public final void Test2() {
is a method (which is never used) and not a constructor.
Change to a constructor declaration like :
public Test2() {
to make the program do something. Then you can go to the next step.
Also use Java naming conventions (like blue instead of Blue).

Add panel to a panel

i'm building a Java program. The core of this program is visualized in a JFrame with a JMenuBar and various JMenuItem and JMenu. The point is that I added a centralPanel to all the frame,but if I add something to the centralPanel it shows only if i resize the main frame, reducing it or enlarging it!
Here's the code:
This is the constructor:
public UserFrame(Sistema system)
{
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
this.setSize(screenSize.width, screenSize.height);
storicoPanel = new JPanel();
carrelloPanel = new JPanel();
carrelloFrame = new JFrame();
pane = new JScrollPane(storicoArea);
close = new JButton("Chiudi");
this.sistema = system;
menu = new JMenuBar();
this.setJMenuBar(menu);
centralPanel = new JPanel();
add(centralPanel);
Here i added the centralPanel, and here, in an ActionListener, i try to add something to it, but it doesnt' work:
public ActionListener createVisualizzaStorico(final ArrayList<Acquisto> array)
{
class Visualize implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
storicoPanel.removeAll();
for(Acquisto a : array)
{
Articolo temp = a.getArticolo();
if(temp instanceof Vacanza)
storicoPanel.add(new VacanzaPanel((Vacanza)temp));
else if(temp instanceof BeneDiConsumo)
storicoPanel.add(new BeneDiConsumoPanel((BeneDiConsumo)temp));
else if(temp instanceof Cena)
storicoPanel.add(new CenaPanel((Cena)temp));
else
storicoPanel.add(new PrestazioniOperaPanel((PrestazioneOpera)temp));
}
centralPanel.add(storicoPanel);
centralPanel.repaint();
Could you please help me? Thanks!
Use a CardLayout instead of trying to add and remove component/panels. It's much cleaner and you don't have to worry about the things that may go wrong, like what you're facing here.
See this example to see how easy and cleaner it is. Also see How to Use CardLayout tutorial
Side Notes
A component can only have one parent container. Though I don't think this is causing a problem for you. It's good to know. First I see you trying to add storicoPanel to a JScrollPane, JScrollPane that you never add to the centerPanel. Then you later add the storicoPanel to the centerPanel. The JScrollPane will no longer be the parent after this.
I'm not sure what you're using this carrelloFrame = new JFrame(); for, but you're class is already a JFrame, why create another?
Just FYI, when adding components dynamically, you need to revalidate() and repaint(). Though, in your situation, I am totally against the adding and removing of components, because this looks like a perfect case for a CardLayout.
Try these..
centralPanel.updateUI(); // or
SwingUtilities.updateComponentTreeUI(getRootPane());
Execute your frame code in SwingUtilities.invokeLater()
Instead of repaint() call updateUI() or
SwingUtilities.updateComponentTreeUI(getRootPane()) to update the
user interface.

Categories

Resources