JPanel help- Drawing rectangles - java

I'm using Graphics for the first time but I have an issue where nothing is showing up besides the background (identified as Bcolor). I'm trying to make a grid with lines using fill(new Rectangle) method with color Lcolor. I ran the debugger, and there doesn't seem to be any syntax, run-time, or logic errors. Anyway to fix this? Thanks!
public static void drawWindow(int Lcolor, int lineSize, int cellSize, int Bcolor){
Graphics g = createWindow(cellSize, Bcolor, lineSize).getGraphics();
Graphics2D g2d = (Graphics2D)g;
for(int i = 0; i <= (frameValues(cellSize, lineSize)[2]); i++){
g2d.setColor(new Color(Lcolor, Lcolor, Lcolor));
g2d.fill(new Rectangle(lineSize * i + cellSize * i, 0, lineSize, frameValues(cellSize, lineSize)[1]));
//.drawLine(xpos,ypos,xsize,ysize)
}//for loop
for(int j = 0; j < (frameValues(cellSize, lineSize)[3]); j++){
g2d.setColor(new Color(Lcolor, Lcolor, Lcolor));
g2d.fill(new Rectangle(0, lineSize * j + cellSize * j, frameValues(cellSize, lineSize)[0], lineSize));
}//for loop
}
and here is the createWindow() method:
public static JPanel createWindow(int cellSize, int Bcolor, int lineSize){
JFrame frame = new JFrame("Evolution Of Life");
frame.setSize(new Dimension(frameValues(cellSize, lineSize)[0], frameValues(cellSize, lineSize)[1]));
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//making it visible
frame.setLocationRelativeTo(null);
frame.setVisible(true);
//creating panel
JPanel panel = new JPanel();
frame.getContentPane().add(panel);
panel.setBackground(new Color(Bcolor, Bcolor, Bcolor));
return panel;
}
//If you need anymore information, I'll be happy to supply.

Don't call getGraphics on a JPanel. If you want to paint to a JPanel, override it's paintComponent method and use the Graphics object passed to that method as explained in the tutorials.
JPanel panel = new JPanel(){
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(...);
g.fill(...);
}
};
frame.add(panel);

Related

Java: Cannot display paintComponent

I have been trying to develop a program that has human stick figure with an arrow. So the issue here is, the drawing under paintComponent doesn't get displayed when ImageIcon as background is added. How do I get to display the painting on top of the background image. My coding is as follows.
public class Drawing
{
public Drawing()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//f.getContentPane().setBackground(new Color(204,229,255));
f.getContentPane().add(new ArrowPanel());
f.setSize(1000,600);
//f.setLocation(200,200);
f.setLayout(new BorderLayout());
f.setContentPane(new JLabel(new ImageIcon("/Users/marian/NetBeansProjects/Drawing/src/drawing/wall.jpg")));
f.setLayout(new FlowLayout());
f.setVisible(true);
}
public static void main(String[] args)
{
new Drawing();
}
}
class ArrowPanel extends JPanel
{
double phi;
int barb;
public ArrowPanel()
{
phi = Math.toRadians(40);
barb = 30;
}
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
int w = getWidth();
int h = getHeight();
Point sw = new Point(w/8, h*7/8);
Point ne = new Point(w*7/8, h/8);
g2.draw(new Line2D.Double(sw, ne));
//drawArrowHead(g2, sw, ne, Color.red);
drawArrowHead(g2, ne, sw, Color.blue);
Ellipse2D.Double head = new Ellipse2D.Double(90,60,20,20);
g2.draw(head);
Line2D.Double body=new Line2D.Double(100,80,100,120);
g2.draw(body);
Line2D.Double arm1=new Line2D.Double(100,100,80,100);
g2.draw(arm1);
Line2D.Double arm2=new Line2D.Double(100,100,120,75);
g2.draw(arm2);
Line2D.Double leg1=new Line2D.Double(100,120,85,135);
g2.draw(leg1);
Line2D.Double leg2=new Line2D.Double(100,120,115,135);
g2.draw(leg2);
}
private void drawArrowHead(Graphics2D g2, Point tip, Point tail, Color color)
{
g2.setPaint(color);
double dy = tip.y - tail.y;
double dx = tip.x - tail.x;
double theta = Math.atan2(dy, dx);
//System.out.println("theta = " + Math.toDegrees(theta));
double x, y, rho = theta + phi;
for(int j = 0; j < 2; j++)
{
x = tip.x - barb * Math.cos(rho);
y = tip.y - barb * Math.sin(rho);
g2.draw(new Line2D.Double(tip.x, tip.y, x, y));
rho = theta - phi;
}
}
}
Im still learning Java, could someone help to solve this problem. Thank you.
If you want to use different layers in your Swing Application, you should use a LayeredPane instead of a JPanel. And you should avoid setting different LayoutManagers. This code sets the last LayoutManager, so the first line is useless:
f.setLayout(new BorderLayout());
f.setContentPane(new JLabel(new ImageIcon("/Users/marian/NetBeansProjects/Drawing/src/drawing/wall.jpg")));
f.setLayout(new FlowLayout());
Here is an article on how to use LayeredPanes Tutorial
You replace your ArrowPanel with the call of setContentPane():
f.getContentPane().add(new ArrowPanel());
...
f.setContentPane(new JLabel(new ImageIcon("/Users/marian/NetBeansProjects/Drawing/src/drawing/wall.jpg")));
Try changing the order of these two statements, EG put the getContentPane() call after the setContentPane().

Alternative to pack()

I am making a terrain generator, and I am loading upwards of a million JPanels into my frame, and that takes more than an hour. I have isolated most of the problem in the pack() method. Are there any alternatives to using it, or maybe a way to do it faster? Here is some of my code:
setLayout(new FlowLayout(0, 0, 0));
System.out.println("Generating...");
Chunk spawnChunk = new Chunk(this.mapSize);
System.out.println("Done\nAdding Tiles...");
for (double[] row : Chunk.tileData) {
for (double d : row) {
int v = (int) (20 - d / 500);
if(v < 0) {
v = 0;
}
else if (v > 20){
v = 20;
}
add(new Tile(v, tileSize));
}
}
System.out.println("Done\nPacking...");
pack();
System.out.println("Done\nRepainting...");
repaint();
System.out.println("Done");
Note: Tile is just a JPanel with a background color
That is a lot of JPanels. My recommendation - if 'Tile is just a JPanel with a background color', then just do the custom drawing yourself using a single JPanel. Override the paintComponent method and use the passed Graphics object to draw the colors.
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
for ( int i = 0; i < numberOfTiles; i++ ){
g.setColor(colorOfCurrentTile);
g.fillRect(left, top, width, height);
}
}

100 Random Circles

After I compiled the previous code it worked but now I cant get the circumference of the circles to change to a different color of whats inside the circle. Any suggestions.
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Dimension d = getSize();
for(int i = 0; i < 100; ++i)
{
Color color = new Color(generator.nextInt(255), generator.nextInt(255), generator.nextInt(255));
g.setColor(color);
int circleSize = generator.nextInt(d.width / 4);
int x = generator.nextInt(d.width - circleSize);
int y = generator.nextInt(d.height - circleSize);
g.fillOval(x, y, circleSize, circleSize);
color = new Color(generator.nextInt(255), generator.nextInt(255), generator.nextInt(255));
g.setColor(color);
g.drawArc(x, y, circleSize, circleSize, 0, 360);
}
}
}
Simply add frame.setPreferredSize(new Dimension (700,500)); right before packing the frame. Those two methods are meant to be used in conjunction. In addition move the adding of the JPanel to after the size is set, this improves code readability and makes more sense if you think about the order of the statements.
public static void main (String[] args)
{
JFrame frame = new JFrame ("CircleFrame");
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
CircleFramePanel panel = new CircleFramePanel();
frame.setPreferredSize(new Dimension (700,500)); // add it here
frame.pack();
frame.getContentPane().add(panel);
frame.setVisible(true);
}

Image not at proper place after rotating (graphics)

I am trying to display two rotating wheels with diameter 512untis at different rates but i am not able to remove the previous drawn image graphics and set the rotated graphics at the correct position.
For now i am doing a rotation with arbitrary angle.
I tried affineTransform and got the rotations but it was weird like all pixels spread away.
Im using a while loop with thread.sleep(). The following is the code :
//The drawSmallCircle and drawBigCircle return two images.
class MyFramePart2 extends JFrame
{
String name;
JPanel big_obj_panel,small_obj_panel;
JLabel bigLabel,smallLabel;BufferedImage imgRet,imgRetSmall;
static double radians,angle,rev,fps,smallAngle,smallRadians;
int numLines,i=0;
MyFramePart2(String frameName,int numStrokes,double revolutions,double frameps)
{
numLines=numStrokes;
smallAngle=smallRadians=angle=radians=Math.toRadians(360/numLines);
rev=revolutions;
fps=frameps;
setSize(1240,720);
setLocation(0,0);
setLayout(null);
getContentPane().setBackground(Color.WHITE);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
big_obj_panel=new JPanel();
big_obj_panel.setLayout(null);
big_obj_panel.setSize(512,512);
big_obj_panel.setLocation(100,100);
big_obj_panel.setBackground(Color.white);
add(big_obj_panel);
imgRet=drawBigCircle();
bigLabel = new JLabel(new ImageIcon(imgRet));
bigLabel.setLayout(null);
bigLabel.setLocation(0,0);
bigLabel.setSize(512,512);
bigLabel.setOpaque(true);
bigLabel.setBackground(Color.white);
big_obj_panel.add(bigLabel);
small_obj_panel=new JPanel();
small_obj_panel.setLayout(null);
small_obj_panel.setSize(512,512);
small_obj_panel.setLocation(700,100);
small_obj_panel.setBackground(Color.white);
add(small_obj_panel);
imgRetSmall=drawSmallCircle();
smallLabel = new JLabel(new ImageIcon(imgRetSmall));
smallLabel.setLayout(null);
smallLabel.setLocation(0,0);
smallLabel.setSize(512,512);
smallLabel.setOpaque(true);
smallLabel.setBackground(Color.white);
small_obj_panel.add(smallLabel);
setVisible(true);
while(i!=5) // suppose to be while true, just checking
{
setVisible(true);
bigLabel.setIcon(new ImageIcon(imgRet));
smallLabel.setIcon(new ImageIcon(imgRetSmall));
try{
Thread.sleep(10);
}
catch(Exception e)
{}
i++;
}
}
#Override
public void paint(Graphics g)
{
super.paint(g);
Graphics2D g2d=(Graphics2D)g;
g2d.translate(256,256);
g2d.rotate(Math.toRadians(20));
g2d.translate(-256,-256);
g2d.drawImage(imgRet,0,0,null);
g2d.dispose();
super.paint(g);
g2d=(Graphics2D)g;
g2d.translate(256,256);
g2d.rotate(Math.toRadians(30));
g2d.translate(-256,-256);
g2d.drawImage(imgRetSmall,0,0,null);
g2d.dispose();
}
public static BufferedImage drawBigCircle()
{
BufferedImage img=new BufferedImage(512,512,BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d=img.createGraphics();
g2d.setColor(Color.black);
g2d.drawOval(0,0,511,511);
Line2D l2d;
while(angle <= 2*Math.PI)
{
l2d=new Line2D.Double(256,256,256+256*Math.cos(angle),256+256*Math.sin(angle));
g2d.draw(l2d);
angle=angle+radians;
}
return img;
}
}
First rule of Swing. Don't block the Event Dispatching Thread. Doing so will make you application look like it's hung and prevent the EDT from processing any repaint requests.
This means, you need some way to schedule updates that doesn't block the EDT
Second rule of Swing. Don't create or modify any UI component from any thread other then the EDT.
Generally, you should avoid overriding the paint method of top level containers like JFrame, apart from everything else, they're not double buffered, meaning your painting will flicker as it's updated. Instead, you should use one of the Swing containers, like JPanel
There are lots of different ways to achieve this. Basically, here I've used three lists, but if I was serious, I would create an object that could maintain all the required information (image, angle an delta)
In order to achieve the actual animation, I've used a javax.swing.Timer. This will trigger an event at least every n periods, but more importantly, it does it within the context of the Event Dispatching Thread. This ensures that all the changes made to the angles are done in way that will prevent any possibility of painting occurring while we're updating the values...
This example rotates the three images at different (random) speeds...
public class TestRotation {
public static void main(String[] args) {
new TestRotation();
}
public TestRotation() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new AnimationPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class AnimationPane extends JPanel {
private List<BufferedImage> images;
private List<Double> angles;
private List<Double> speed;
public AnimationPane() {
images = new ArrayList<>(5);
images.add(createWheel(50, 4));
images.add(createWheel(50, 3));
images.add(createWheel(50, 6));
angles = new ArrayList<>();
speed = new ArrayList<>();
for (int index = 0; index < images.size(); index++) {
angles.add(0d);
speed.add(Math.random() * 5d);
}
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (int index = 0; index < angles.size(); index++) {
double angle = angles.get(index);
double delta = speed.get(index);
angle += delta;
angles.set(index, angle);
}
repaint();
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = 0;
int y = 0;
for (int index = 0; index < images.size(); index++) {
BufferedImage image = images.get(index);
double angle = angles.get(index);
// This is important. Basically we going to grab a isolated snap shot
// of the current graphics context. This means any changes we make
// will not affect the original graphics context (other then painting)
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
AffineTransform at = new AffineTransform();
at.translate(x, y);
at.rotate(Math.toRadians(angle), image.getWidth() / 2, image.getHeight() / 2);
g2d.setTransform(at);
g2d.drawImage(image, 0, 0, this);
g2d.dispose();
x += image.getWidth();
}
}
}
protected Point2D calculateOutterPoint(int radius, double angel) {
int x = Math.round(radius / 2);
int y = Math.round(radius / 2);
double rads = Math.toRadians((angel + 90));
// This determins the length of tick as calculate from the center of
// the circle. The original code from which this derived allowed
// for a varible length line from the center of the cirlce, we
// actually want the opposite, so we calculate the outter limit first
double fullLength = (radius / 2d);
// Calculate the outter point of the line
double xPosy = (x + Math.cos(rads) * fullLength);
double yPosy = (y - Math.sin(rads) * fullLength);
return new Point2D.Double(xPosy, yPosy);
}
public BufferedImage createWheel(int radius, int spokes) {
BufferedImage img = new BufferedImage(radius, radius, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.black);
g2d.drawOval(0, 0, radius - 1, radius - 1);
Point2D center = new Point2D.Double(radius / 2d, radius / 2d);
double angle = 360d / spokes;
for (int index = 0; index < spokes; index++) {
Point2D p = calculateOutterPoint(radius, index * angle);
g2d.draw(new Line2D.Double(center, p));
}
g2d.dispose();
return img;
}
}

Add a JPanel to a Graphics Panel and making the JPanel Transparent except for objects

I am trying to make a Blackjack Game and way I want to design my program is with a graphics panel (Images, drawing of cards, etc.) and on top of that panel a JPanel with buttons. I want this JPanel to be transparent so that the Graphics Panel underneath is Visible but the JButtons do not turn transparent as well.
If someone can send me in the right direction?
Graphic Layer:
public class GraphicsBoard {
String[] fileName = { "cards.png", "BlackJackBoard.png" };
ClassLoader cl = GraphicsBoard.class.getClassLoader();
URL imgURL[] = new URL[2];
Toolkit tk = Toolkit.getDefaultToolkit();
Image imgCards, imgBG;
public GraphicsBoard() throws Exception {
for (int x = 0; x < imgURL.length; x++)
imgURL[x] = cl.getResource("pictures/" + fileName[x]);
imgCards = tk.createImage(imgURL[0]);
imgBG = tk.createImage(imgURL[1]);
}
public void paintComponent(Graphics g) {
g.drawImage(imgBG, 0, 0, 550, 450, 0, 0, 551, 412, this);
Graphics2D g2 = (Graphics2D) g;
for (int x = 0; x <= 550; x += 50) {
g2.drawLine(x, 0, x, 450);
g2.drawString("" + x, x + 5, 20);
}
for (int y = 5; y <= 450; y += 50) {
g2.drawLine(0, y, 550, y);
g2.drawString(" " + y, 0, y + 20);
}
}
}
Button Layer:
public class OverBoard extends JPanel implements ActionListener{
JButton btnDeal = new JButton("Deal");
public OverBoard(){
btnDeal.addActionListener(this);
add(btnDeal);
setOpaque(false);
}
}
I want the ButtonLayer to be on top of the GraphicLayer.
I want this JPanel to be transparent so that the Graphics Panel
underneath is Visible but the JButtons do not turn transparent as
well.
an OverlayLayout JPanel will do what you descibe.
there are a few ways, proper could be to
use GlassPane, have to consume() or redispatch KeyEvents
JLayer (Java7), based on JXLayer(Java6)

Categories

Resources