Is there any way I can make translucent JInternalFrame uing swing?
All I found is option for JFrame(not internal one) which is not what I need.
You should be able to use a JLayer. You could start with the layout painting a fully opaque layer the same color as the background of the desktop pane. Then you change the alpha value to approach cell until you have full transparency.
See the section from the Swing tutorial on How to Decorate Components With the JLayer Class for more information and an example of painting with transparency.
If you only care about the background you can use the Alpha Container when using components with transparency:
JPanel content = new JPanel( new BorderLayout() );
content.setBackground( new Color(0, 0, 0, 0) );
internalFrame.setContentPane(new AlphaContainer(content));
internalFrame.setOpaque(false);
You can then change the alpha value of the content panel to your desired transparency.
Edit:
Here is may attempt at animating the transparency of an internal frame and its components:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class TransparentInternalFrame extends JInternalFrame implements ActionListener
{
static int openFrameCount = 0;
static final int xOffset = 30, yOffset = 30;
private float alpha = 0.0f;
private Timer timer = new Timer(500, this);
public TransparentInternalFrame()
{
super("Document #" + (++openFrameCount), true, true, true, true);
setSize(300,300);
setLocation(xOffset * openFrameCount, yOffset * openFrameCount);
setVisible( true );
}
#Override
public void paint(Graphics g)
{
g.setColor( getDesktopPane().getBackground() );
g.fillRect(0, 0, getWidth(), getHeight());
Graphics2D g2 = (Graphics2D)g.create();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
super.paint(g2);
}
public void showFrame()
{
timer.start();
}
public void hideFrame()
{
alpha = 0.0f;
repaint();
}
#Override
public void actionPerformed(ActionEvent e)
{
alpha += .05f;
alpha = Math.min(1.0f, alpha);
System.out.println(alpha);
if (alpha >= 1.0f)
timer.stop();
repaint();
}
private static void createAndShowGUI()
{
JDesktopPane desktop = new JDesktopPane();
desktop.setBackground( Color.YELLOW );
TransparentInternalFrame tif = new TransparentInternalFrame();
desktop.add( tif );
tif.add(new JButton("Hello"), BorderLayout.PAGE_START);
JButton show = new JButton( "Show Internal Frame" );
show.addActionListener( new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
tif.showFrame();
}
});
JButton hide = new JButton( "Hide Internal Frame" );
hide.addActionListener( new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
tif.hideFrame();
}
});
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(show, BorderLayout.PAGE_START);
frame.add(desktop);
frame.add(hide, BorderLayout.PAGE_END);
frame.setLocationByPlatform( true );
frame.setSize(500, 500);
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
Related
I am trying to add a Rectangle in the panel by button press and remove it with another one. It should work but it doesn't render anything, and I absolutely don't know why.
Can someone explain what I am doing wrong and give me some nice tips what I can improve with my code?
public class GUI extends JPanel {
public static boolean isRecVisible = false;
public static void main(String[] args) {
createGui();
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g);
g2d.drawRect(10, 10, 200, 200);
}
public static void createGui() {
int frameWidth = 550;
int frameHeight = 400;
int buttonWidth1 = 250;
int buttonHeight1 = 30;
int buttonWidth2 = 500;
int buttonHeight2 = 30;
int displayWidth = frameWidth - 20;
int displayHeight = frameHeight - 105;
GUI drawRec = new GUI();
JFrame f = new JFrame("Rectangle");
JPanel p = new JPanel();
JPanel display = new JPanel();
JButton addRec = new JButton("Add Rectangle");
JButton removeRec = new JButton("Remove Rectangle");
JButton colorRec = new JButton("Color Rectangle");
f.add(p);
p.add(addRec);
p.add(removeRec);
p.add(colorRec);
p.add(display);
display.setBackground(Color.LIGHT_GRAY);
f.setSize(frameWidth, frameHeight);
f.setLocationRelativeTo(null);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
display.setBounds(frameWidth / 2 - displayWidth / 2, 10, displayWidth, displayHeight);
addRec.setBounds(frameWidth / 2 - buttonWidth1 / 2 - 250 / 2, frameHeight - 85, buttonWidth1, buttonHeight1);
removeRec.setBounds(frameWidth / 2 - buttonWidth1 / 2 + 250 / 2, frameHeight - 85, buttonWidth1, buttonHeight1);
colorRec.setBounds(frameWidth / 2 - buttonWidth2 / 2, frameHeight - 60, buttonWidth2, buttonHeight2);
addRec.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (isRecVisible == false) {
isRecVisible = true;
display.add(drawRec);
display.repaint();
System.out.println("Rectangle has been drawn!");
} else {
System.out.println("Rectangle has already been drawn!");
return;
}
}
});
removeRec.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (isRecVisible == true) {
isRecVisible = false;
System.out.println("Rectangle has been removed!");
} else {
System.out.println("Rectangle has already been removed");
return;
}
}
});
}
}
display.add(drawRec);
display.repaint();
When you add (or remove) components to a visible frame then the basic logic is:
display.add(...);
display.revalidate();
display.repaint(); // sometimes needed
The revalidate() is the key method because it invokes the layout manager so the size/location of the component can be set.
However, that still won't fix the problem because your custom panel doesn't have a preferred size, so there is nothing to paint for your component.
You need to override the getPreferredSize() method of your custom panel to return the preferred size of your custom component. So in your case you might set the preferred size to be (220, 220) so the rectangle is centered in the panel.
Read the section from the Swing tutorial on Custom Painting for more information and complete working examples.
Note: the tutorial example will also show you how to better structure your code to make sure the GUI is created on the Event Dispatch Thread.
Rather than adding or removing components, it would make more sense here to add the custom painted panel on construction, and use the isRecVisible boolean as a flag to test for drawing the rectangle.
Something like shown here:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GUI extends JPanel {
public static boolean isRecVisible = false;
public static void main(String[] args) {
createGui();
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g);
if (isRecVisible) {
g2d.drawRect(10, 10, 200, 200);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(600,400);
}
public static void createGui() {
int frameWidth = 550;
int frameHeight = 400;
GUI drawRec = new GUI();
drawRec.setBackground(Color.LIGHT_GRAY);
JFrame f = new JFrame("Rectangle");
JPanel p = new JPanel();
JButton addRec = new JButton("Add Rectangle");
JButton removeRec = new JButton("Remove Rectangle");
JButton colorRec = new JButton("Color Rectangle");
f.add(p, BorderLayout.PAGE_START);
p.add(addRec);
p.add(removeRec);
p.add(colorRec);
f.add(drawRec);
f.setSize(frameWidth, frameHeight);
f.setLocationRelativeTo(null);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
addRec.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
isRecVisible = true;
drawRec.repaint();
}
});
removeRec.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
isRecVisible = false;
drawRec.repaint();
}
});
}
}
New to Java and very new to Java's GUI classes. I'm making a GUI to showcase a few games, but am having difficulties switching panels. I read about CardLayout but I'm having an issue implementing it because I can't get the JPanels that hold the different games' GUIs to send their events back to the class that uses the CardLayout. (This is probably where I'm going wrong -- I can't get my head around how to structure this properly.)
This is my main menu (called mainContainer):
This is the overall structure of the GUI driver:
public class CasinoDriverGUI {
//CardLayout is here in the main method Container contentPane.add(cardLayout)
public static void main(String[] args) throws IOException
//MainContainer is MenuScreen: GridBagLayout for nice button placement
static class MainContainer extends JPanel implements ActionListener{...}
static class CrapsContainer extends JPanel implements ActionListener{...}
static class PokerContainer extends JPanel implements ActionListener{...}
//Button with custom look
class CButton extends JButton
}//end CasinoDriverGUI
Here is the main method: It grabs an image from a website and then adds the menu screen (mainContainer) to the contentPane. The menu screen uses GridBagLayout, but it's where the button components are added. Because of this, I can't figure out how to get the CardLayout of the contentPane to listen to the menu screen's buttons. I tried using ContainerListener but that seemed to be a dead end.
public class CasinoDriverGUI {
public static void main(String[] args) throws IOException {
// load the texture resource image
System.out.println("Please wait, Loading Texture : http://www.pngall.com/wp-content/uploads/2016/04/Casino-PNG-Pic.png");
MainContainer.textureImg = ImageIO.read(new URL("http://www.pngall.com/wp-content/uploads/2016/04/Casino-PNG-Pic.png"));
System.out.println("Loading finished. Starting the Casino!");
MainContainer.textureImg = MainContainer.textureImg.getSubimage(0, 0, 580, 309);
// Starting the Swing GUI in the EDT
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final CardLayout cardLayout = new CardLayout();
JFrame frame = new JFrame("Midnight Casino");
// frame about the size of background src image
frame.setPreferredSize(new Dimension(580, 329));
final Container contentPane = frame.getContentPane();
contentPane.setLayout(cardLayout);
MainContainer mainContainer = new MainContainer();
mainContainer.setPreferredSize( frame.getPreferredSize() );
contentPane.add(mainContainer, "mainContainer");
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
As I have it so far, I have just tried using the "menu screen" (mainContainer) to instantiate all the games' panels and use an ActionListener on some buttons to simply call thisGame.setVisible(true). but this is forcing the window to be minimized and re-opened for any change to be detectable.Edit: fixed this.
Any advice on how I can restructure this code to be able to switch the panels from the menu screen to the different game's panels? (Code is below, but the craps and poker GUIs are incomplete.. just using the code as placeholders.
public class CasinoDriverGUI {
public static void main(String[] args) throws IOException {
// load the texture resource image
System.out.println("Please wait, Loading Texture : http://www.pngall.com/wp-content/uploads/2016/04/Casino-PNG-Pic.png");
MainContainer.textureImg = ImageIO.read(new URL("http://www.pngall.com/wp-content/uploads/2016/04/Casino-PNG-Pic.png"));
System.out.println("Loading finished. Starting the Casino!");
MainContainer.textureImg = MainContainer.textureImg.getSubimage(0, 0, 580, 309);
// Starting the Swing GUI in the EDT
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final CardLayout cardLayout = new CardLayout();
JFrame frame = new JFrame("Midnight Casino");
// frame about the size of background src image
frame.setPreferredSize(new Dimension(580, 329));
final Container contentPane = frame.getContentPane();
contentPane.setLayout(cardLayout);
MainContainer mainContainer = new MainContainer();
mainContainer.setPreferredSize( frame.getPreferredSize() );
contentPane.add(mainContainer, "mainContainer");
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
static class MainContainer extends JPanel implements ActionListener
{
public BufferedImage gradientImage = null;
public static BufferedImage textureImg; // static for ease
public static boolean loadingFinished = false;
protected JButton pokerJBtn;
protected JButton crapsJBtn;
CrapsContainer crapsContainer;
PokerContainer pokerContainer;
public MainContainer() {
setBorder(new EmptyBorder(50, 50, 50, 50)); // setting the insets
setLayout(new GridBagLayout());
// working with GridBagConstraints
GridBagConstraints labCnst = new GridBagConstraints();
GridBagConstraints txtCnst = new GridBagConstraints();
labCnst.ipady = txtCnst.ipady = 10;
labCnst.fill = GridBagConstraints.HORIZONTAL;
labCnst.gridwidth = 1;
labCnst.weightx = 0.3;
labCnst.gridx = 2;
labCnst.gridy = 2;
labCnst.ipady = 13;
labCnst.insets = new Insets(0, 0, 0, 150);
pokerJBtn = new CButton("5-Card Poker");
add(pokerJBtn, labCnst);
labCnst.gridx = 2;
labCnst.gridy = 20;
labCnst.ipady = 13;
labCnst.insets = new Insets(0, 0, 0, 150);
crapsJBtn = new CButton("Craps");
add(crapsJBtn, labCnst);
crapsContainer = new CrapsContainer();
pokerContainer = new PokerContainer();
add(crapsContainer);
add(pokerContainer);
crapsContainer.setVisible(false);
pokerContainer.setVisible(false);
//Add Action Listeners
crapsJBtn.addActionListener(this);
pokerJBtn.addActionListener(this);
}
public void changeCompFont(JComponent comp)
{
comp.setForeground(Color.WHITE);
comp.setFont(getFont().deriveFont(Font.BOLD, 13));
}
// To PAINT THE TEXTURE ABOVE THE COMPONENTS
#Override
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2d = (Graphics2D)g.create(); // cloning
Rectangle2D txRect = new Rectangle2D.Double(0, 0, textureImg.getWidth(), textureImg.getHeight());
TexturePaint txPaint = new TexturePaint(textureImg, txRect);
g2d.setPaint(txPaint);
//make the texture transparent
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.233f));
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.dispose();// disposing the graphics object
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if(gradientImage==null || gradientImage.getHeight() != getHeight() )
{
gradientImage = createGradientImg();
}
g2d.drawImage(gradientImage, 0, 0, getWidth(), getHeight(), this);
g2d.dispose();
}
public BufferedImage createGradientImg()
{
BufferedImage image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
// background gradient paint, linear gradient paint for the background
// Gradient paint rendering could be made more optimized
LinearGradientPaint lgrPaint = new LinearGradientPaint(0.0f, 0.0f, getWidth(), getHeight(),
new float[] { 0.0f, 0.5f, 0.6f, 1.0f },
new Color[] { new Color(0x0530E),// new Color[] { new Color(0x002AFF),
new Color(0x0A31B),
new Color(0x0A31B),
new Color(0x0530E ) });
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setPaint(lgrPaint);
//g2d.shear(0.2, 0);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.dispose();
g2d.drawImage(textureImg, 0, 0, getWidth(), getHeight(), null);
return image;
}
#Override
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == pokerJBtn)
{
pokerContainer.setVisible(true);
}
else if (e.getSource() == crapsJBtn){
this.setVisible(false);
invalidate();
crapsContainer.setVisible(true);
revalidate();
repaint();
}
}
}
//Either Flow, Border, or GridBag Layout
static class CrapsContainer extends JPanel implements ActionListener
{...}
//Either Flow, Border, or GridBag Layout
static class PokerContainer extends JPanel implements ActionListener
{...}
//Custom Button to change aesthetic look
class CButton extends JButton
{...}
}
I have JFrame, which contains a Jscrollpane which in turn contains a Jpanel with image being displayed in it. All the mouse events and drawing is respect to the Jpanel cordinates. Now, I want to put a guide lines marker on top of the ViewPort, The marker should remain constant irrespective of the image being zoomed or panned. What is the best way to do it? Thanks in advance.
You can do custom painting on the viewport of the scroll pane:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
public class ViewportBackground
{
private static void createAndShowUI()
{
JViewport viewport = new JViewport()
{
#Override
protected void paintChildren(Graphics g)
{
super.paintChildren(g);
int w = this.getWidth();
int h = this.getHeight();
g.drawLine(0, 0, w, h);
}
};
JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewport(viewport);
scrollPane.setViewportView( new JLabel( new ImageIcon(...) ) );
JFrame frame = new JFrame("Viewport Background");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( scrollPane );
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Suppose I have a JPanel in a JFrame. When I invoke a method that changes the preferred size of that JPanel, it does not change.
The code looks something like this:
public class SomePanel extends JPanel{
public SomePanel(){
setPreferredSize( new Dimension( 390, 40 ) );
setBackground( Color.BLACK );
}
public void expand(){
setPreferredSize( new Dimension( 390, 200 ) );
}
public static void main( String args[] ){
JFrame frame = new JFrame();
frame.setSize( 450, 500 );
frame.setLayout( new FlowLayout() );
SomePanel somePanel = new SomePanel();
frame.add( somePanel );
frame.setVisible( true );
somePanel.expand();
}
}
Is there something that I have to do first? I have tried so check the size of the JPanel when expand() is invoked. The height of the JPanel before and after setting the preferred size remains at 40.
I have also tried to use a Dimension variable, and that did not work either.
Dimension dimension;
public SomePanel(){
dimension = new Dimension( 390, 40 );
...
}
public expand(){
dimension.setSize( 390, 200 );
setPreferredSize( dimension );
}
Add frame.pack(); after somePanel.expand(); in your main() method. It will be done.
You need to invalidate the container hierarchy to make it re-layout the components.
Simply call invalidate followed by revalidate on the component you have changed.
Here's a small example...
public class TestComponentHierarcy {
public static void main(String[] args) {
new TestComponentHierarcy();
}
public TestComponentHierarcy() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(new Test());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Test extends JPanel {
private Dimension size = new Dimension(10, 10);
public Test() {
setLayout(new GridBagLayout());
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
size.width += 10;
size.height += 10;
invalidate();
revalidate();
}
});
}
#Override
public Dimension getPreferredSize() {
return size;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
}
}
}
+1 to all.
I usually use a combination of:
revalidate() and pack(). (see #GagandeepBali and #StanislavL answer here for more reasoning as to my choice of revalidate()) as for pack() this allows for my JFrame to be sized to fit the contents.
do not call setPreferredSize rather override getPreferredSize of JPanel.
also do not call setSize(..) on JFrame use correct LayoutManager which adjusts to all added components size and than simply call pack() before setting JFrame visible.
And lastly but not stressed enough warp creation and manipulation of Swing components in SwingUtilities.invokeXXX block / Event Dispatch Thread
Here is an example I made:
Basically a JPanel which overrides getPreferredSize and has a method setPanelSize(int w,int h) which changes variables in JPanel instance to return new Dimensions for getPreferredSize. after that I call revalidate() and pack() on JFrame to refelect changes:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
initComponents();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void initComponents() {
final JFrame frame = new JFrame();
frame.setTitle("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final MyPanel myPanel = new MyPanel();
final JButton changeSizeButton = new JButton("Change size to 300x300");
changeSizeButton.addActionListener(new ActionListener() {
boolean resized = false;
#Override
public void actionPerformed(ActionEvent ae) {
if (resized) {
myPanel.setPanelSize(200, 200);
resized = false;
changeSizeButton.setText("Change size to 300x300");
} else {
myPanel.setPanelSize(300, 300);
resized = true;
changeSizeButton.setText("Change size to 200x200");
}
frame.revalidate();
frame.pack();
}
});
frame.add(myPanel);
frame.add(changeSizeButton, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
class MyPanel extends JPanel {
private int width, height;
public MyPanel() {
super(true);
width = 200;
height = 200;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
public void setPanelSize(int width, int height) {
this.width = width;
this.height = height;
}
}
I've hit a wall (in my brain) trying to update my board on button presses. Am I right in thinking that the GameBoard class is the one that needs to be repaint()ed?
GameBoard.java
public class GameBoard extends Panel {
static Compass compass = new Compass();
private static final long serialVersionUID = 1;
Graphics2D g2d;
static final Dimension WINDOW_SIZE = new Dimension(1150, 800);
public void boardMaker() throws Exception {
JFrame frame = new JFrame("Display image");
JPanel panel = new JPanel();
/* unimportant stuff
.....
*/
//
DieRoll roll = new DieRoll("Roll Dies");
roll.setC(compass);
roll.setG2D(g2d);
//
Button button = new Button("new");
button.setGameBoard(this);
JPanel buttonPanel = new JPanel();
buttonPanel.add(button);
buttonPanel.add(roll);
buttonPanel.setPreferredSize(new Dimension(200,100));
frame.getContentPane().add(buttonPanel, BorderLayout.NORTH);
//
frame.getContentPane().add(panel);
frame.setVisible(true);
}
public void paint(Graphics g) {
// not important I think
}
}
Button.java
public class Button extends JButton implements ActionListener {
private static final long serialVersionUID = 1L;
JPanel panel = new JPanel();
JFrame frame = new JFrame();
Compass c = new Compass();
GameBoard gb = new GameBoard();
Button(String text) {
this.setText(text);
this.addActionListener(this);
}
void setGameBoard(GameBoard gb) {
this.gb = gb;
}
#Override
public void actionPerformed(ActionEvent e) {
gb.g2d.setColor(Color.black);
gb.g2d.fillRect(100, 100, 100, 200);
gb.repaint();
}
}
This gives a null pointer exception. So any idea how to repaint my GameBoard? I'm not mad if I've to rewrite everything because of stupidity! ;)
Thanks
You have the wrong idea about how to draw in Java. Components like Panels draw themselves, and all drawing takes place on the UI thread.
Check out this tutorial: docs.oracle.com/javase/tutorial/2d/index.html
The article Painting in AWT and Swing may offer some perspective on application-triggered painting. The example below illustrates the principle. Note that setForeground() calls repaint() automatically because the foreground color is a bound property, but you can always call it yourself.
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class SwingPaint {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame f = new JFrame();
final GamePanel gp = new GamePanel();
f.add(gp);
f.add(new JButton(new AbstractAction("Update") {
#Override
public void actionPerformed(ActionEvent e) {
gp.update();
}
}), BorderLayout.SOUTH);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
private static class GamePanel extends JPanel {
private static final Random r = new Random();
public GamePanel() {
this.setForeground(new Color(r.nextInt()));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 240);
}
public void update() {
this.setForeground(new Color(r.nextInt()));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Dimension size = this.getSize();
int d = Math.min(size.width, size.height) - 10;
int x = (size.width - d) / 2;
int y = (size.height - d) / 2;
g.fillOval(x, y, d, d);
g.setColor(Color.blue);
g.drawOval(x, y, d, d);
}
}
}