I have the following code. Basically I have a frame which has a background image. I also have three panels within the frame: panels 1, 2 and 3. 2 & 3 work fine as I haven't subclassed them. However, panel 1 as soon as I subclassed it i.e. put the logic inside the paintComponent method of JPanel stopped working as that method is never called and foo is never printed. I'm not able to figure out why. Would appreciate your help. I've tried a few suggestions from other similar threads and they haven't helped.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) throws IOException {
JFrame.setDefaultLookAndFeelDecorated(true);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int fooPanelX = 5;
int fooPanelY = 160;
int fooPanelWidth = 470;
int fooPanelHeight = 305;
int bar0PanelX = 5;
int bar0PanelY = 550;
int bar0PanelWidth = 230;
int bar0PanelHeight = 210;
int bar1PanelX = bar0PanelX * 2 + bar0PanelWidth + bar0PanelX;
int bar1PanelY = bar0PanelY;
int bar1PanelWidth = bar0PanelWidth;
int bar1PanelHeight = bar0PanelHeight;
JPanel panel1 = new Panel1(fooPanelX, fooPanelY, fooPanelWidth, fooPanelHeight);
JPanel panel2 = new JPanel();
panel2.setBackground(Color.WHITE);
panel2.setLocation(bar0PanelX, bar0PanelY);
panel2.setSize(bar0PanelWidth, bar0PanelHeight);
panel2.setOpaque(false);
panel2.setBorder(BorderFactory.createLineBorder(Color.WHITE));
panel2.setBounds(bar0PanelX, bar0PanelY, bar0PanelWidth, bar0PanelHeight);
JPanel panel3 = new JPanel();
panel3.setBackground(Color.WHITE);
panel3.setLocation(bar1PanelX, bar1PanelX);
panel3.setSize(bar1PanelWidth, bar1PanelHeight);
panel3.setOpaque(false);
panel3.setBorder(BorderFactory.createLineBorder(Color.WHITE));
panel3.setBounds(bar1PanelX, bar1PanelY, bar1PanelWidth, bar1PanelHeight);
JLabel imagePanel = new JLabel(new ImageIcon(ImageIO.read(new File("image.png"))));
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == 27) {
System.exit(0);
}
}
});
frame.setContentPane(imagePanel);
frame.getContentPane().add(panel1);
frame.getContentPane().add(panel2);
frame.getContentPane().add(panel3);
frame.setLocation((int) (screenSize.getWidth() * 0.75),
(int) (screenSize.getHeight() * 0.25));
frame.pack();
frame.setVisible(true);
}
#SuppressWarnings("serial")
static class Panel1 extends JPanel {
int x, y, w, h;
public Panel1(int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
#Override
public void paintComponent(Graphics graphics) {
System.out.println("foo");
super.paintComponents(graphics);
setBackground(Color.WHITE);
setLocation(x, y);
setSize(w, h);
setOpaque(true);
setBorder(BorderFactory.createLineBorder(Color.WHITE));
}
}
}
Update: If you aren't able to find the issue then please could you provide me with an alternative way of doing the following. I need a frame with a background image and three panels on top of the background image. The three panels have to have pixel perfect locations and sizes on the background image to look right. That's it pretty much. I'll be repainting the three panels but the background image will remain the same.
Well, the problem is that you are not using an appropriate LayoutManager.
JLabel does not come with any LayoutManager by default. So when you add your Panel1, it has a size of 0x0 and is located in (0,0) and since no LayoutManager will change that, it will keep that size and location. With empty bounds, your component is never painted, hence your paintComponent method is never called.
Now, you should NEVER do this in paintComponent:
setBackground(Color.WHITE);
setLocation(x, y);
setSize(w, h);
setOpaque(true);
setBorder(BorderFactory.createLineBorder(Color.WHITE));
Do that in the constructor or some other method. paintComponent is meant for "painting a component", not changing its properties.
I decided to tackle the problem in a very different way. This is how I did it. I startedc completely from scratch with my code. I created a JFrame instance and a Canvas instance (the canvas was subclassed). In the canvas I used drawImage() to apply the background image. Then for each of the three areas that I wanted to animate on the background image, instead of creating three JPanels, I simply used fillRect() within the canvas to fill the right areas on the image. That's it. Nice and simple. The repaint() every second does flickr on the three areas and that's the next challenge. I'm guessing I have to use double buffering but it's not something I've used before so I'll look into that next. Anyway, using a single canvas in place of three JPanels proved a heck of a lot simpler and the reason I was able to do that was because the background image provided everything else visually. All I had to do was drawImage() and fillRect(). Thanks for all contributions.
Update: I have now completed this task. There was one thing I changed about the above. While attempting to double buffer with Canvas I had a few issues: the usual "component must have valid peer" exception. While looking into that I learnt that one should not use Canvas in Swing and that the practice of using it was mixing AWT and Swing. So I swapped it out for JComponent (as I didn't need anything that JPanel offered). And as Swing is double buffered by default my work was complete. No flicker and simplified code.
Related
First off, I am new to JFrame and all the associated classes so I am still learning how to do this.
My current goal is to draw multiple images on a single JFrame. So far, I can get test2.png to draw, but not test1.png. Any suggestions or help understanding JFrame is appreciated. This is my main class:
package com.osj.oneshotjava;
import java.awt.Dimension;
import javax.swing.JFrame;
/**
*
* #author BCG04
*/
public class actorTest {
public static void main(String []args){
JFrame jFrame = new JFrame("OSJ actor test");
jFrame.setPreferredSize(new Dimension(640, 480)); // sets window size
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Actor2 Background = new Actor2(jFrame, "test1.png");
Actor2 testActor = new Actor2(jFrame, "test2.png");
jFrame.pack(); // automatically adjusts window size (also sets window size based on the maximum and minimum sizes)
jFrame.setVisible(true);
}
}
And this is Actor2:
package com.osj.oneshotjava;
import java.awt.BorderLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
*
* #author BCG04
*/
public class Actor2 { //Purpose: make it easer to add multiple images to a single JFrame using only a single call to Actor2's constuctor rather than repeating the same section of code for each image.
private BufferedImage image = null;
private JLabel jLabel = null;
public Actor2(JFrame jFrame, String filename){
try
{ // try to load a image 'filename' into 'image'
image = ImageIO.read(new File(filename));
}
catch (Exception e)
{
e.printStackTrace(); // if loading fails, print the error
System.exit(1); // then exit with an error code 1 'unsuccessful exit'
}
ImageIcon imageIcon = new ImageIcon(image); // create a new ImageIcon that contains 'image'
JPanel jPanel = new JPanel();
jLabel = new JLabel();
jLabel.setIcon(imageIcon); // set JLabel 'jLabel' to contain 'imageIcon'
jPanel.add(jLabel);
jFrame.getContentPane().add(jPanel, BorderLayout.CENTER); // makes window visible?
}
public JLabel getJLabel(){
return jLabel;
}
}
Edit:
-removed Thread.sleep(1000); and setLocation(90, 90); since they were not relevant to the question or the problem and I originally had them in to test whether I could move images.
-removed jLabel.setBounds as it did not seem to do anything.
+added a comment clarifying Actor2's goal.
I'd like to clarify my end goal, I would like to create a simple 2d game that uses Java.
Here is a complete, self contained example that is close to what you're after. It is to demonstrate the use of a layout manager.
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
public class DuelingJLabels{
public static void startGui(){
JFrame frame = new JFrame();
JPanel scene = new JPanel();
Actor red = new Actor(Color.RED);
Actor blue = new Actor(Color.BLUE);
//scene.setLayout( null );
scene.add(red.image);
scene.add(blue.image);
//scene.setPreferredSize( new Dimension(512, 512) );
frame.add(scene, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
static class Actor{
int x, y;
JLabel image;
public Actor(Color c){
BufferedImage a = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB);
Graphics g = a.getGraphics();
g.setColor(c);
g.fillOval(0, 0, 64, 64);
image = new JLabel();
image.setIcon(new ImageIcon(a));
image.setLocation( x, y );
image.setSize( 64, 64);
image.addMouseListener( new MouseAdapter(){
#Override
public void mouseClicked(MouseEvent evt){
x = x+64;
if(x>=448){
x = 0;
y += 64;
}
image.setLocation(x, y);
}
});
}
}
public static void main(String[] args){
EventQueue.invokeLater( DuelingJLabels::startGui );
}
}
Take note of the line scene.setLayout(null); if you run the example with that line commented out, then you will see two circles side by side. That is because we are letting swing handle the layout. scene is a JPanel with a FlowLayout by default.
Now when you click the circles, nothing happens* because we tell the new position but the layout manager resets the position.
*Actually they move sometimes, but if you trigger a re-validation then they get moved by the layout manager.
So now remove the comment on scene.setLayout(null); and notice the difference.
The frame is tiny, and we have to manually resize it to see our scene.
There is only one circle.
If you click on the circle, it moves.
That's because we have told swing to not use a layout manager for the JPanel scene. That means it will not reposition the components in the scene for us, and it will not adjust the sizes for us either.
The other line that is commented setPreferredSize makes scene tell the parent component a size it would like to be at. If you uncomment that line then the JFrame will not start out incredibly small. You should only use that with custom components, otherwise you can end up conflicting with the layout manager.
Another tool, which I have found usefull is the JLayeredPane because it gives you some depth. I also think the example is good.
Finally, another technique for putting custom graphics arbitrarily is to #Override paintComponent. That way you can draw whatever, where-ever on your component.
Here is a piece of code :
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class QuitButton extends JPanel implements ActionListener
{
static JButton button = new JButton("Panic");
Color[] colors = new Color[9];
boolean pressed = false;
public QuitButton()
{
button.addActionListener(this);
colors[0] = Color.RED;
colors[1] = Color.BLUE;
colors[2] = Color.GREEN;
colors[3] = Color.YELLOW;
colors[4] = Color.BLACK;
colors[5] = Color.PINK;
colors[6] = Color.MAGENTA;
colors[7] = Color.ORANGE;
colors[8] = Color.CYAN;
}
#Override
public void actionPerformed(ActionEvent e)
{
pressed = true;
}
public static void main(String args[])
{
JFrame frame = new JFrame("Do NOT Panic!!");
QuitButton qb = new QuitButton();
frame.add(qb);
frame.add(button);
frame.setLayout(new FlowLayout());
frame.setSize(400, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
//frame.pack();
button.requestFocus();
qb.gameLoop();
}
public void gameLoop()
{
while (true)
{
repaint();
try
{
Thread.sleep(200);
} catch (Exception e)
{
}
}
}
public void paint(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
if (pressed == false)
{
super.paint(g2d);
g2d.setColor(Color.GRAY);
g2d.fillRect(0, 0, 400, 400);
} else
{
super.paint(g2d);
Random r = new Random();
int min = 0;
int max = 8;
int index = r.nextInt(max - min) + min;
g2d.setColor(colors[index]);
g2d.fillRect(0, 0, 400, 400);
}
}
The purpose of this program: The rectangle should be grey before but when I click the panic button colours should start changing.
Please don't get confused with the name of the class which is QuitButton.
But my rectangle is not occupying the entire window. Instead I am getting a teeny tiny rectangle like this : http://g.recordit.co/xJAMiQu6fM.gif
I think it is because of the layout I am using and I haven't specified anywhere that the button will be on top. Probably that's why they are coming side by side. I am new to GUI creation and thank you for your help.
You seem to be making some guesses on how to do this, which is not a good way to learn to use a library. Your first step should be to check the relevant tutorials on this, most of which will be found here: Swing Info Since this appears to be homework, I'm not going to give you a code solution but rather suggestions on how to improve:
Override paintComponent, not paint since the latter gives double buffering and is less risky (less painting of borders and child component problems)
In your paintComponent override, be sure to call the super's paintComponent method first to clear "dirty" pixels.
Use a Swing Timer, not a while loop for your game loop. This will prevent your while loop from freezing the Swing event thread, a problem that can freeze your program. Google the tutorial as it is quite helpful.
Do your randomization within the ActionListener's code (here likely the ActionListener for your Swing Timer), not within the painting code. The painting code should not change the state of the object but rather should only display the object's state.
FlowLayout will respect a component's preferredSize, and your component's preferred size is 0,0 or close to it. Change this. Best to override public Dimension getPreferredSize() and return a Dimension that matches your Rectangle's size.
Avoid using "magic" numbers, such as for your rectangle's size, and instead use constants or fields.
Call repaint() within your Timer's ActionListener so the JVM knows to paint the component.
Just trying to draw some lines to the screen.
I've checked to ensure all the relevant code's being run
I've tried calling repaint (and ensuring that's being run)
Since this is a JSplitPane, the layout must be the JSplitPane layout
I'm setting the color to ensure it isn't drawing using the background color.
I've checked the height and width to ensure its size isn't 0 or something
I've tried drawing text as well; same result
I've changed the coordinates all over the place, tried both arbitrary and proportional values
Or at least I think. Swing is unintuitively quirky. I'd use AWT, but I need the specificity Swing offers. Anyway, the code. It's just a split pane, which is actually displaying - resizable and all - but the contents of the top pane (the only one I've attempted to put anything in) don't show.
package derange;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.*;
public class Derange {
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("Derange");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Display the window.
frame.setExtendedState(frame.getExtendedState() | JFrame.MAXIMIZED_BOTH);
frame.pack();
frame.setVisible(true);
//Create a split pane with the two scroll panes in it.
PanelScore scorePane = new PanelScore();
JScrollPane instrumentPane = new JScrollPane();
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
scorePane, instrumentPane);
splitPane.setOneTouchExpandable(true);
splitPane.setDividerLocation((frame.getHeight() / 4) * 3 );// Three-quarters of the way down
splitPane.setDividerSize(20);
//Provide minimum sizes for the two components in the split pane
Dimension minimumSize = new Dimension(frame.getWidth(), frame.getHeight()/ 2);//width, height
scorePane.setMinimumSize(minimumSize); //Score takes up at least half the screen
instrumentPane.setMinimumSize(new Dimension(0,0));//no minimum size on the instrument panel; collapsible
frame.getContentPane().add(splitPane);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
.
package derange;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Insets;
import javax.swing.JScrollPane;
#SuppressWarnings("serial")//wtf is this needed for?
public class PanelScore extends JScrollPane{
public int strings = 6;
public void drawStaffTablature(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.black);
int xStart = 30;//insets.left;
int xEnd = getParent().getWidth() - 30;
int yCoord = this.getHeight() / 2;
System.out.println(this.isShowing());
//Space between tablature lines
int lineSpacing = 15;
//Space between staffs.
int staffSpacing = 60;`enter code here`
for(int x = 0; x < strings; x++){
g2d.drawLine(xStart, yCoord + (lineSpacing * x), xEnd, yCoord + (lineSpacing * x));
//System.out.println("String: " + (x + 1));
g.drawString("Test", xStart, yCoord); //change the co-odrinates
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawStaffTablature(g);
}
}
Short answer, don't extend from JScrollPane, a JScrollPane contains single component known as a JViewport, which covers the most of the scroll pane (the rest is taken up by the JScrollBars
Instead, try extending from something like JPanel.
I'd also advise you against using anything like int xEnd = getParent().getWidth() - 30; within your paint code, the Graphics context is translated to the components location, making the top/left corner 0x0 and clipped to the components current width and height
So I wanted to write the basics for a 2D game so I could look back at later if I forget and so I could create one without having to look over the same tutorials over and over again.
Since the first game I made was a snake game almost a year ago(I've asked for help with this before), I looked back on it to find quite the mess! I only used one class for everything and I neglected to use comments to tell myself what each part of the code is doing what.
I was using the tutorial from: http://www.java-gaming.org/index.php?topic=25802.0, but they use bufferStrategy, which I haven't used before, and Key Event / Key Adapter,which I was told to use ActionListener for the Snake Game instead.
I know the main classes that I would be changing are ButtonHandler, Draw, and Player. I've already edited a few things: added limits to how far the square can go (so it doesn't go off screen) and a Variables class so that the other classes inherit it so I can change the size of the screen and square easily. I've tried coping and pasting the Timer into it's own class, but since I have very little knowledge of how to use a Timer, it doesn't work (obviously).
My questions are:
Can bufferStrategy work with Timer? Could I put a Timer with ActionListener in it's own class? Can bufferStrategy work like a Timer?
Oh, and on top of that, what's the best way to make a start screen and inventory screen? How does it fit in with the main screen or should I just make a separate screen that pops up for both (if that is easier)?
Edit:
Alright, sorry, I was out watching a play. Here's the Draw class from the tutorial plus some edits for the variables. I was wondering which class the Timer would go into. Since the bufferStrategy was done in the Draw class, would the Timer be there as well? This also includes my unfinished version of a start screen.
Draw class
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Draw extends Variables
{
JFrame frame;
Canvas canvas;
BufferStrategy bufferStrategy;
private int WIDTH = w;
private int HEIGHT = h;
private int PWIDTH = pw;
private int PHEIGHT = ph;
Color start = Color.decode("#00BFFF");
Draw(){
frame = new JFrame("Game");
JPanel panel = (JPanel) frame.getContentPane();
panel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
panel.setLayout(null);
canvas = new Canvas();
canvas.setBounds(0, 0, WIDTH, HEIGHT);
canvas.setIgnoreRepaint(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
panel.add(canvas);
canvas.createBufferStrategy(2);
bufferStrategy = canvas.getBufferStrategy();
canvas.requestFocus();
canvas.setBackground(Color.black);
canvas.addKeyListener(new ButtonHandler());
}
void render() {
Graphics2D g = (Graphics2D) bufferStrategy.getDrawGraphics();
if (startScreen == 0)
{
g.clearRect(0, 0, WIDTH, HEIGHT);
render(g);
g.dispose();
bufferStrategy.show();
}
else
{
canvas.setBackground(start);
}
}
protected void render(Graphics2D g){
g.setColor(Color.white);
g.fillRect(Instances.player.getX(), Instances.player.getY(), PWIDTH, PHEIGHT);
}
}
Can bufferStrategy work with Timer?
Yes.
Could I put a Timer with ActionListener in it's own class?
Yes.
Can bufferStrategy work like a Timer?
No.
Post some code with a more specific question for a more detailed answer.
I am still trying to get a repaint() method to work in a separate class with a class that extends the JComponent. I have placed a couple of post on here and so far I haven't been able to get the code to work. I have gotten some good advice. I am placing below what I have so far.
Main Class 1:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
public class DDHGenericFrame extends JFrame {
private static final long serialVersionUID = 1L;
DDHGenericPanel d = new DDHGenericPanel(); /*User defined class that is above*/
public DDHGenericFrame() {
initUI();
}
public final void initUI() {
add(d);//Adds the panel to the JFrame
setSize(650,350);
setTitle("Lines");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
DDHGenericFrame ex = new DDHGenericFrame();
ex.setVisible(true);
}
}
Class 2:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
class DDHGenericPanel extends JPanel {
private static final long serialVersionUID = 1L;
public JButton aButton1;
public JButton aButton2;
public TestPane tPane = new TestPane();
DDHGenericPanel(){
System.out.println("DDH Generic JPanel");
aButton1 = new JButton();
aButton1.setText("Button 1");
aButton1.addActionListener(new myButtonActionListener1());
add(aButton1);
aButton2 = new JButton();
aButton2.setText("Button 2");
aButton2.addActionListener(new myButtonActionListener2());
add(aButton2);
System.out.println("Before the setDraw!!!");
tPane.setDraw();
System.out.println("After the setDraw!!!");
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("paintComponent of DDHGenericPanel.java");
}
}
class myButtonActionListener1 implements ActionListener {
public TestPane tPane = new TestPane();
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("Button 1 -- Before the setDraw!!!");
tPane.setDraw();
System.out.println("Button 1 -- After the setDraw!!!");
}
}
class myButtonActionListener2 implements ActionListener {
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("Button1 clicked 2");
}
}
Class 3: (I had this one embedded in the same files as the class above -- it will be separate when I have the finished code)
/**
* This class will draw a cricle with the repaint method
* #author DDH
*/
class TestPane extends JComponent {
private static final long serialVersionUID = 1L;
private static final int LINE_THICKNESS = 4;
private static final int LINE_GAP = 10;
private Color lineColor = Color.red;
/**
* This method will draw the circle with coordinated (0,0)
* #param none
* #return none
*/
public void setDraw() {
repaint();//This should call the paintComponent() that is below and paint a circe but it does not for some reason.
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int radius = 10;
BufferedImage buffer = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = buffer.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint (RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
Ellipse2D circle = new Ellipse2D.Float(0, 0, radius,radius);
Shape clip = g2d.getClip();
g2d.setClip(circle);
AffineTransform at = g2d.getTransform();
g2d.setTransform(AffineTransform.getRotateInstance(
Math.toRadians(45),
radius / 2, radius / 2));
int gap = LINE_GAP;
g2d.setColor(Color.WHITE);
g2d.fill(circle);
g2d.setColor(lineColor);
//g2d.setStroke(new BasicStroke(LINE_THICKNESS));
for (int index = 0; index < 10; index++) {
int x1 = index*gap-(LINE_THICKNESS/2);
int y1 = 0;
int x2 = index*gap+(LINE_THICKNESS/2);
int y2 = radius;
int width = x2 - x1;
int height = y2 - y1;
g2d.fillRect(x1, y1, width, height);
//g2d.drawLine(index * gap, 0, index * gap, getRadius());
}
g2d.setTransform(at);
g2d.setClip(clip);
g2d.dispose();
g.drawImage(buffer, 0, 0, this);
}
}
Frome what I have read and what people have posted this should work. Is there a way to force it to paint right away. Repaint() sometimes has a little bit of a delay. I want to use this as the start of a game and I have to be able to create an ArrayList of Circles and then repaint them immediately.
Currently this will only draw one circle in the top (0,0) coordinates.
Doug Deines Hauf
Is there a way to force it to paint right away.
It will paint right away as soon as the GUI is visible. There is nothing special that you need to do. There is no need for a setDraw() method. All components will automatically be painted when the GUI is displayed.
System.out.println("Before the setDraw!!!");
tPane.setDraw();
System.out.println("After the setDraw!!!");
That code does nothing. The GUI isn't visible yet so there is nothing to paint. There is no reason for you do invoke a repaint unless you actually change a property of a component on a visible GUI.
public void setDraw() {
repaint();
}
There is no reason to create a method that simply does a repaint(), get rid of this method. That is NOT what I suggested in your last posting. I said you create a method to change a property that will affect the outcome of the painting of the component.
I gave you an example, like when you use setForeground(), the method changes the Color of the text to be painted, so repaint() is automatically invoked when the color is changed.
Get rid of all the complex painting code in your paint component and then try to do a simple
graphics.drawString();
Don't be playing with rotations and clips (even I have problem with these concepts and if not done correctly you may not get anything painted) until you get something basic working. Then once you get that working you do something more complicated, one step at a time until you understand the basics. Don't write a complex program until you get something simple working.
Also, I don't know why you are attempting to draw from a buffered image. Just draw using the Graphics object that is passed into the paintComponent() method. There is no need to use a BufferedImage, Swing is already double buffered so you are just complicating your code.
Have you read the Custom Painting tutorial yet? It contains a working example.
Edit:
Having said all the above you still have two fundamental problems:
you don't add the component to the panel
the component doesn't have a preferred size so there is nothing to paint. You need to override the getPreferredSize() method to return a reasonable size for the component that you want to paint.
Even these two fixes don't solve the problem of your complex painting, but at least now I can get a simple drawstring(...) to work.