Java swing.JFrame only paints content on resize of window - java

I have the following program. It is supposed to print red text on a green ground. When the program opens, I only see the green background but not the red text on it. Once the window is resized and by this recalculated, the red text appears.
It works properly if I use a JPanel within the window and add a component there. If the colors are set in paintComponent then, everything works fine.
So where is the problem, if I draw on the JFrame directly. Am I missing a first "update" or something? It looks like there is some information missing on first draw of the window (the additional text) of which the program only becomes aware once the window is recalculated and redrawn.
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class PaintAWT extends JFrame {
PaintAWT() {
this.setSize(600, 400);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
// Set background color:
// If you don't paint the background, one can see the red text.
// If I use setBackground I only see a green window, until it is
// resized, then the red text appears on green ground
this.getContentPane().setBackground(new Color(0,255,0));
// Set color of text
g.setColor(new Color(255,0,0));
// Paint string
g.drawString("Test", 50, 50);
}
public static void main(String[] args) {
new PaintAWT();
}
}

You should NOT be setting properties of a component in a painting method. Painting methods are for painting only. Don't use setBackground().
You should be setting the background of the content pane when you create the frame.
Whenever you do custom painting you should also be overriding the getPreferredSize() method to return the size of the component.
You should also not be extending JFrame. You only extend a class when you add functionality to the class.
Start by reading the section from the Swing tutorial on Custom Painting fore more information and working examples. The examples will show you how to better structure your code to follow Swing conventions.

You should move setBackground to constructor. Setting of background in paint method is a bad approach.
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class PaintAWT extends JFrame {
PaintAWT() {
this.setSize(600, 400);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Set background color:
// If you don't paint the background, one can see the red text.
// If I use setBackground I only see a green window, until it is
// resized, then the red text appears on green ground
this.getContentPane().setBackground(new Color(0,255,0));
this.setVisible(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
// Set color of text
g.setColor(new Color(255,0,0));
// Paint string
g.drawString("Test", 50, 50);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new PaintAWT();
}
});
}
}

Related

JComponent disappear when resizing?

Hi i am a beginner in java, here I have my program, however, when I try resizing the panel my text just disappears?
Moreover, how can i draw a thick green line under my text which will stay under the text even when resizing, I am very clueless?
import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
public class Groovy
{
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame= new JFrame("Shearing Word Demo");
frame.setResizable(true);
frame.setSize(new Dimension(500,250));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Toolkit it=Toolkit.getDefaultToolkit();
Dimension d=it.getScreenSize();
int w=frame.getWidth(), h=frame.getHeight();
frame.setLocation(d.width/2-w/2, d.height/2-h/2);
frame.add(new JComponent(){
#Override public void paintComponent(Graphics g){
Graphics2D g2=(Graphics2D) g;
g2.setColor(Color.magenta);
g2.setFont(new Font("Comic Sans MS",Font.BOLD,44));
g2.drawString("Feeling Groovy!", 110,125 );
}
});
frame.setVisible(true);
}
});
}
}
how can i draw a thick green line under my text which will stay under the text even when resizing, I
If you do custom painting then the basic steps you need to follow would be something like:
get the FontMetrics of the Graphics object using the getFonTMetrics() method
get the rectangle of text using the getStringBounds(...) method
use the setStroke(...) method of the Graphics2D object to set the thickness of the line to paint
use the drawLine(...) method Graphics2D object to paint the line based on the location of the text and the information of the Rectangle from the string bounds
An easier solution for displaying text is to use a JLabel. Then you can set the Border of the label. Read the section from the Swing tutorial on How to Use Borders for more information.
Note when doing custom painting with a JComponent you are also responsible for clearing the background of the component. So the first painting in the method should be:
g2.setColor( getBackground() );
g2.fillRect(0, 0, getWidth(), getHeight());
Most people use a JPanel for custom painting then you can just use:
super.paintComponent(g);
to make sure the background is cleared.

How to draw a line on a panel after pack() has been called?

I am writing a small GUI in Java, using Swing components. My program uses several overlapping panels, the sizes of which are decided upon at the point that 'pack()' is called.
My problem is this. I need to know the dimensions of a particular JPanel prior to pack(), as I need to draw a line vertically down it. I cannot get this height dimension however until pack is called.
I have put in a System.out.println(myPanel.getSize()) call before the pack command & it returns (0, 0). When put in after, it returns the actual dimensions of the panel... as you would expect.
So, how does one draw a line on a panel down its entire length, either without knowing its length to begin with, or somehow doing so after pack has been called?
You can achieve this by adding a ComponentListener to the panel. Its componentResized() event is triggered whenever the panel is resized. And inside componentResized() method you will always get the actual size of the panel. Try below example and see it yourself.
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
public class PanelResize
{
public static void main(String[] args)
{
CustomPanel panel = new CustomPanel();
panel.addComponentListener(new ComponentAdapter()
{
#Override
public void componentResized(ComponentEvent e)
{
System.out.println(panel.getSize());
panel.repaint();
}
});
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(panel);
f.setBounds(300, 200, 400, 300);
f.setVisible(true);
}
}
class CustomPanel extends JPanel
{
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.blue);
g.drawLine(getWidth()/2, 0, getWidth()/2, getHeight());
}
}

Add GUI with Swing, but unsure of the sequence to take

I'm building a GUI for a data processing algorithm. I can instantiate the window, give it a background, title, etc., but when I try adding panels to it, I run into trouble. What I'm really looking for more than a proofreader is a suggestion for the sequence in which to build, configure, and add objects in Java Swing so that they behave correctly, in a generic sense. So, is this the best way to build a JFrame with a different-colored panel in it?
Declare JFrame
Set JFrame color (background color)
Declare JPanel (box to represent data graphically)
Set JPanel color (box color)
Add JPanel to JFrame
Set JFrame to visible = true
It makes sense intuitively but it doesn't seem to work, no matter what I do. I've found step-by-step instructions elsewhere but they tend to explain what to type more than why you're typing it, so you get a very narrow understanding of what's going on. Thanks for any help!
Below is the full code; I hesitated to post it because I'd begun experimenting with Graphics2D and it isn't well-commented, but if it helps:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.*;
import javax.swing.border.TitledBorder;
public class GUI extends JFrame
{
JFrame mainWindow = new JFrame();
JPanel backgroundPanel = new JPanel();
JPanel subPanel = new JPanel();
Color background = new Color(40,40,40);
Color subWindow = new Color(255, 255, 255);
TitledBorder title = BorderFactory.createTitledBorder("title");
Rectangle rect1 = new Rectangle(10, 10, 40, 40);
Graphics2D g;
public static void main (String[] args)
{
new GUI();
}
public GUI()
{
initializeGUI();
}
private void initializeGUI()
{
mainWindow.setSize(1340, 880);
backgroundPanel.setBackground(background);
subPanel.setBackground(subWindow);
subPanel.setBorder(title);
mainWindow.setTitle("Ed");
mainWindow.setLocationRelativeTo(null);
mainWindow.setDefaultCloseOperation(EXIT_ON_CLOSE);
mainWindow.add(backgroundPanel);
backgroundPanel.add(subPanel);
updateGUI();
}
public void updateGUI()
{
mainWindow.setVisible(false);
mainWindow.setVisible(true);
}
public void paintComponent(Graphics g)
{
this.g.setColor(subWindow);
this.g.fill(rect1);
this.g = (Graphics2D) g;
}
}
Let's break this down....
public class GUI extends JFrame {
JFrame mainWindow = new JFrame();
There is no need to extend from JFrame as you are neither using it nor are you adding any value to the class.
This...
public void paintComponent(Graphics g) {
this.g.setColor(subWindow);
this.g.fill(rect1);
this.g = (Graphics2D) g;
}
is doing nothing and will never be called, as nothing you've extended from implements a paintComponent method (that is, JFrame does not have a paintComponent methd) (and you class is not attached to anything displayed on the screen anyway). Also, you should NEVER maintain a reference to ANY Graphics context you did not create yourself.
The reason that subPanel is appearing so "small" is because it has not definable size, aside from the border.
You could rectify this in one of three ways...
You could change the layout manager of backgroundPanel to something like BorderLayout
You could override the getPreferredSize method of the subPanel to return a more suitable size or
You could add other components to it and let the layout manager figure it out...
In any case, you should have a look at Laying Out Components Within a Container.
You should also have a look at Painting in AWT and Swing and Performing Custom Painting for more details about how painting is done in Swing

How to put circle into middle of Frame by using methods getWidth and getHeight?

I have a problem with put drawn circle into middle of Frame by using methods getWidth() and getHeight(). I tried something with Image package but no idea where to implement this methods:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Frame;
import java.awt.Image;
public class Circle extends Frame {
public Circle() {
setSize(400,400);
setLocationRelativeTo(null);
setVisible(true);
}
public Color() {
}
public void paint(Graphics g) {
g.setColor(Color.ORANGE);
g.fillOval(200, 200, 200, 200);
}
public static void main(String[] args) {
Circle c = new Circle();
c.paint(null);
}
}
Then I have to use method setColor(Color) and Color class constructor to make random color of this circle (after every run of this program). I opened Color constructor but there is an error :/
Better to extract all the paint functionality to a JComponent here to take full advantage of Swing's optimized paint model using paintComponent.
The Circle is actually a JFrame. Inside in its constructor, a new component is created which handles the painting of the circle. The Color constructor has been removed as this is invalid syntax.
The circle co-ordinates are start in the top left-hand corner and take the full available width & height for drawing.
Also would recommend using lightweight Swing components over old-style AWT component.
public class Circle extends JFrame {
public Circle() {
setSize(400, 400);
add(new CirclePanel());
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
Circle c = new Circle();
}
}
class CirclePanel extends JComponent {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.ORANGE);
g.fillOval(0, 0, getWidth(), getHeight());
}
}
See: Painting in AWT and Swing
Simply call getWidth() and getHeight() from within the paint(...) method and use the results returned for your fillOval(...) parameters.
But having said that, it's a better idea to draw in a Canvas that is added to the Frame. And having said that, it's much better still to draw in the paintComponent(...) method of a JPanel that is added to the contentPane of a JFrame in a Swing application.

Turning a JFrame black when opening another window

I wan't to make my main JFrame become darken when the focus is on another window.
This is an example from the game Football Manager 2012. First the main window is selected and it looks like it should, then when it is loading, it turns darker and unselectable. I wan't to have this effects on my own application, but im not really sure how, not even sure what to google?
Im guessing its a JWindow that appears and the JFram becomes unselectable in the background. I'm planing to use it on a help-window in my application, that is a JWindow right now.
Andrew Thompson has the right idea, only it's easier to use the glass pane feature of your frame's JRootPane. Here's some working code: In your frame class, invoke
getRootPane().setGlassPane(new JComponent() {
public void paintComponent(Graphics g) {
g.setColor(new Color(0, 0, 0, 100));
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
});
Then, to show the "curtain", invoke
getRootPane().getGlassPane().setVisible(true);
In the code above, change the alpha transparency value of 100 in order to find the suitable darkness.
..wan't the JFrame to go back to normal after the new window is closed. I tried setVisible(false) but it didn't work.
It works in this example.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class ShadowedFrame extends JFrame {
ShadowedFrame() {
super("Shadowed Frame");
getRootPane().setGlassPane(new JComponent() {
public void paintComponent(Graphics g) {
g.setColor(new Color(0, 0, 0, 100));
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
});
JButton popDialog = new JButton("Block Frame");
popDialog.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
getRootPane().getGlassPane().setVisible(true);
JOptionPane.showMessageDialog(ShadowedFrame.this, "Shady!");
getRootPane().getGlassPane().setVisible(false);
}
});
setContentPane(popDialog);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationByPlatform(true);
setSize(350,180);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ShadowedFrame().setVisible(true);
}
});
}
}
(Untested, but..) Seems like a good task for a JLayeredPane. Create a JComponent that is set transparent and add that to the top level of the layered pane. In the paintComponent(Graphics) method of the component, set a semi-transparent color and fill the full area with it. In normal use (non-dimmed), call customComponent.setVisible(false).
Update
Or, as Ingo pointed out, use the glass pane.
I'm guessing its a JWindow that appears and the JFrame becomes unselectable in the background
It is more likely a modal JDialog. When a modal dialog is visible, the frame/window that is the owner becomes inaccessible (cannot be clicked on).

Categories

Resources