So I have this class inside a class which is an implementation of JPanel.
private static class Line extends JComponent {
private static final long serialVersionUID = 1L;
#Override
public void paintComponent(Graphics g) {
System.out.println("Pozvan paintComponent()");
g.setColor(Color.YELLOW);
g.drawLine(20, 20, 100, 20);
super.paintComponent(g);
}
}
This is a snippet of code which creates a single instance of Line:
Line line = new Line();
line.setOpaque(true);
add(line);
I really don't know what I am doing wrong here. When I draw a rectangle, everything is nicely drawn.
when I set the height to remotely big number it works.
The default size of a Swing component is (0, 0). Since the size is 0, there is nothing to paint.
g.drawLine(20, 20, 100, 20);
Using the above information this means your component needs a size of (120, 40). That is, width = 20 + 100 and height = 20 + 20, in order for the component to be painted.
I added line.setBounds(20, 20, 80, 50);
Only part of your line will be painted, since you set the width to 80, not 120.
Read the section from the Swing tutorial on Custom Painting for more information and examples.
Related
I'm trying to draw vertical lines to separate days in a week on a JFrame. The code seems fine as no error but when I run it, it output a frame like the picture below. Am I missing anything?
public class WeekToView extends JFrame{
public WeekToView(){
setTitle("Sheffield Dental Care"); //set title
Toolkit toolkit = Toolkit.getDefaultToolkit();
Dimension screenDimensions = toolkit.getScreenSize();
setLocation(new Point(screenDimensions.width*1/4, screenDimensions.height*1/4)); //set location based on screen size
JPanel container = new JPanel();
JScrollPane scrPane = new JScrollPane(container);
getContentPane().add(scrPane);
double size[][] = {{150, 150, 150, 150, 150}, // Columns
{100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100}}; // Rows
container.setLayout(new TableLayout(size));
String daysInWeek[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"};
JLabel daysInWeekLabels[] = new JLabel[daysInWeek.length];
for (int i = 0; i < daysInWeek.length; i++) {
daysInWeekLabels[i] = new JLabel(daysInWeek[i],SwingConstants.CENTER);
}
container.add(daysInWeekLabels[0], "0,0");
container.add(daysInWeekLabels[1], "1,0");
container.add(daysInWeekLabels[2], "2,0");
container.add(daysInWeekLabels[3], "3,0");
container.add(daysInWeekLabels[4], "4,0");
setSize(780,600); //set size based on screen size
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false); //unresizable
setVisible(true);
}
public void paintComponent(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawLine(getWidth()/5,0,getWidth()/5,getHeight());
g2.drawLine(getWidth()*2/5,0,getWidth()*2/5,getHeight());
g2.drawLine(getWidth()*3/5,0,getWidth()*3/5,getHeight());
g2.drawLine(getWidth()*4/5,0,getWidth()*5/5,getHeight());
}
}
There is no paintComponent() method in a JFrame. Whenever you attempt to override a method you should always use #Override before the method name. You will get a compile error if you don't override the method correctly.
You could override paint() but in general don't try to do custom painting in the paint() method of a JFrame.
Instead custom painting is done by overriding the paintComponent() method of the panel that you add to the frame.
Better yet you can use a JTable, which already provides you with a row/column based component.
I would like to round the top two corners on a JFrame for a project I am currently working on. I am currently rounding all four corners using setShape(new RoundRectangle2D.Double(0, 0, 200, 252, 30, 30)); but I do not want the bottom two rounded I want the to be a normal corner.
you can combine shapes to get this.By combining roundered rectangle with a normal rectangle you can make a rectangle without bottom two rounded corners.
for example
public class example extends JFrame{
public example() {
this.setUndecorated(true);
this.getContentPane().setBackground(Color.red);
Area shape1 = new Area(new RoundRectangle2D.Double(0, 0, 200, 252, 30, 30));
Area shape2 = new Area(new Rectangle(0, 252-30, 200, 100));
shape1.add(shape2);
this.setShape(shape1);
this.setSize(300, 400);
}
public static void main(String[] args) {
new example().setVisible(true);
}
}
alternatively you can give smaller height to the frame than RoundRectangle rectangle .so you can't see bottom of the RoundRectangle .and then you can get desired output
First off I would like to say that I understand I am asking a lot so any help would be appreciated and I thank you for your time. I am extremely grateful.
Anyway I am creating a game for my A2 coursework, most commonly known as Checkers. I have completed my code and everything works as I had planned except that the CheckerBoard itself as well as the checkerpieces do not appear to be showing.
The section of were my board should be present is just a black space. Although my board does not appear to be displaying, all of the actions I perform on it such as clicking certain section produces the planned response, and although I've checked through my code I cannot work out what I've done wrong.
Anyway if anyone could possibly spot my mistake or perhaps give me some advice I would be extremely grateful. Thank you
As I of course can't upload my entire code I will do snippets of where I think the problem might lie or just important sections. Thank you
CheckerBoard content = new CheckerBoard(); // Sets the CheckerBoard values into the content to be used in the next line
application.setContentPane(content); // Container holds the values together, Content pane of the CheckerBoard
application.pack(); // Use preferred size of content to set size of application.
Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
application.setLocation( (screensize.width - application.getWidth())/2,
(screensize.height - application.getHeight())/2 );
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); // Sets so that the application can be exited when the application is closed
application.setResizable(false); // This makes it so that the user can't change the application's size.
application.setVisible(true); // Sets it so that the application can actually be seen
The code above is placed within a "public static void main(String[] args)"
Then below that I have:
public CheckerBoard() {
// This is going to be a constructor, this constructor will set the layout manager for the panel to be null, it will then add components to the panel
// and it will set their bounds.
setLayout(null); // So that it will match my requirement specification, I will do the layout myself
setBackground(new Color(0,120,0)); // Dark Green Background colour.
setPreferredSize(new Dimension(350,250)); // The size of the Panel
BoardComplete checkerboardData = new BoardComplete();
add(checkerboardData); // This will create the components and add them to the content pane
add(NewGameButton);
add(ResignButton);
add(MessageDisplay);
// I will now have to produce a method to set the position and size of each component by calling its setBounds() method
checkerboardData.setBounds(20,20,164,164); // Sets the board dimensions
NewGameButton.setBounds(210, 60, 120, 30);
ResignButton.setBounds(210, 120, 120, 30);
MessageDisplay.setBounds(20, 200, 350, 30);
}
And then finally I have a another public class called BoardComplete which contains all the relevant code involving the actionlistners ect. used:
BoardComplete() {
setBackground(Color.BLACK);
addMouseListener(this);
ResignButton = new JButton("Resign");
ResignButton.addActionListener(this);
NewGameButton = new JButton("New Game");
NewGameButton.addActionListener(this);
MessageDisplay = new JLabel("",JLabel.CENTER);
MessageDisplay.setFont(new Font("Serif", Font.BOLD, 14));
MessageDisplay.setForeground(Color.green);
checkerboardData = new DataForCheckers();
MakeaNewGame();
}
I understand that this is a lot to ask but any help would be greatly appreciate and I would be extremely grateful. Thank you.
Edit due to comment: This is the code for my Paint Class:
public void PaintCheckerBoard(Graphics g) {
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// This will draw a two-pixel black border around the edges of the canvas.
g.setColor(Color.black);
g.drawRect(0,0,getSize().width-1,getSize().height-1);
g.drawRect(1,1,getSize().width-3,getSize().height-3);
// Draw the squares of the checkerboard and the checkers.
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
if ( row % 2 == col % 2 )
g.setColor(Color.LIGHT_GRAY);
else
g.setColor(Color.GRAY);
g.fillRect(2 + col*20, 2 + row*20, 20, 20);
switch (checkerboardData.PieceLocation(row,col)) {
case DataForCheckers.RED:
g.setColor(Color.RED);
g.fillOval(4 + col*20, 4 + row*20, 15, 15);
break;
case DataForCheckers.BLACK:
g.setColor(Color.BLACK);
g.fillOval(4 + col*20, 4 + row*20, 15, 15);
break;
case DataForCheckers.RED_KING:
g.setColor(Color.RED);
g.fillOval(4 + col*20, 4 + row*20, 15, 15);
g.setColor(Color.WHITE);
g.drawString("K", 7 + col*20, 16 + row*20);
break;
case DataForCheckers.BLACK_KING:
g.setColor(Color.BLACK);
g.fillOval(4 + col*20, 4 + row*20, 15, 15);
g.setColor(Color.WHITE);
g.drawString("K", 7 + col*20, 16 + row*20);
break;
}
}
}
// If there is a game in progress, highlight the legal moves that the player can make.
// It can be seen that in this process, LegalMoves is never null while a game is in progress
if (CheckerMatchInProgress) {
/* First, draw a 2-pixel cyan border around the pieces that can be moved. */
g.setColor(Color.cyan);
for (int i = 0; i < LegalMoves.length; i++) {
g.drawRect(2 + LegalMoves[i].fromCol*20, 2 + LegalMoves[i].fromRow*20, 19, 19);
g.drawRect(3 + LegalMoves[i].fromCol*20, 3 + LegalMoves[i].fromRow*20, 17, 17);
}
// If a piece is selected to be moved, for example if ChosenRow>=0, then
// draw a 2-pixel white border around that piece, and draw a green border
// around each square that the piece can be legally moved to.
if (ChosenRow >= 0) {
g.setColor(Color.white);
g.drawRect(2 + ChosenColumn*20, 2 + ChosenRow*20, 19, 19);
g.drawRect(3 + ChosenColumn*20, 3 + ChosenRow*20, 17, 17);
g.setColor(Color.green);
for (int i = 0; i < LegalMoves.length; i++) {
if (LegalMoves[i].fromCol == ChosenColumn && LegalMoves[i].fromRow == ChosenRow) {
g.drawRect(2 + LegalMoves[i].toCol*20, 2 + LegalMoves[i].toRow*20, 19, 19);
g.drawRect(3 + LegalMoves[i].toCol*20, 3 + LegalMoves[i].toRow*20, 17, 17);
}
}
}
}
} // end PaintCheckerBoard()
So looking through your code on the other site, your custom paint method never seems to be getting called from anywhere. You're supposed to override the paintComponent method from the Component class (JPanel is a subclass of Component). This paintComponent method will be called whenever swing thinks, or is told to redraw something.
So, add this code to your BoardComplete class:
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
PaintCheckerBoard(g);
}
super.paintComponent will do anything swing would do to paint this component (which at this point is just drawing the background). And then you pass the Graphics object to your own custom paint method, that method will draw your entire game on the Graphics object, and swing will display whatever is drawn on there for you.
So now you have to remember also to call repaint() every time something in your game changes. The repaint() method will just tell swing he should repaint something (note: this tells the awt thread it should repaint the component, so it happens asynchronously from where youre calling repaint()).
If youre still confused, you should probably look up some information or tutorials on how to draw with awt/swing using this method.
Why does this code output two lines that are the same size?
import java.awt.*;
import javax.swing.*;
public class G2Scale extends JPanel{
public static void main(String args[]) {
G2Scale g = new G2Scale();
g.setPreferredSize(new Dimension(200, 200));
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(g);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.BLUE);
g2.scale(0.5, 1.0);
g2.drawLine(5, 50, 100, 50);
g2.setColor(Color.GREEN);
g2.scale(1.0, 1.0);
g2.drawLine(5, 100, 100, 100);
}
}
I would expect these lines to be different sizes because they are scaled differently. From what I am seeing I am thinking that the scale is based off of the previous scale. Am I right about this?
If this is true, how would I get the second line to be scaled to what I thought it should be?
Thanks
All methods you call on a Graphics object that don't output something but instead change a property of it (like setColor, setFont, and so on), are stored in the context of the graphics object. Actually, you should think of a Graphics instance as a graphics context that contains and abstract all the information you need to draw into the screen.
So basically, yes, your second scale is based on the first, since the first one changes the graphics context and the second one acts on top of it.
There're two ways to change this behavior:
Reset the state your Graphics instance by aplying the opposite of your first change (in this case, the inverse scalling).
Make a copy of the Graphics object before applying any context change.
I'm more inclined to the second option, but here're some examples of both:
Graphics2D g2 = (Graphics2D) g;
// resetting the context state
g2.scale(0.5, 1.0);
g2.drawLine(5, 50, 100, 50);
g2.scale(2, 1.0);
// using a copy of the context
// note: casting is mandatory since 'create' returns a Graphics object
Graphics2D g2copy = (Graphics2D)g2.create();
g2copy.scale(1.0, 1.0);
g2copy.drawLine(5, 100, 100, 100);
// this one doesn't have any scale applied
g2.drawLine(5, 150, 100, 150);
I working on a project in which I have to simulate a memory manager and show some memory snapshots. I have created a draw class via examples I have found here in which I override the paintComponet(). Everything draws fine.
I would like to be able to draw a rectangle to represent a memory partition and then overlay another rectangle over top to represent an incoming job (ie Job1 is in this partition3). What seems to occur is that I add the partition first (which will always be the case) and then when I add the job it will sit behind the partition block. Is there a way other than drawing the Job first to shift these after the job is created?
Here is the paint override
#Override public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
// set up rendering to allow anti-aliasing
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// create the rectangle to represent the memory partition block
// x = address position h = amount of memory (y & w are predefined for the display block)
Rectangle2D rect = new Rectangle2D.Double(x, y, w, h); // create the rectangle
g2d.setPaint(partColor); // set it's color
g2d.fill(rect); // fill it in
// create the transparency for the text
Composite comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .4f);
g2d.setComposite(comp);
// draw the text with color, type and size and center the text in the block created above
g2d.setPaint(Color.black);
g2d.setFont(new Font("Tahoma", Font.PLAIN, 12));
g2d.drawString(text, (int)((w / 2) - (text.length()/2)), (int)h/2);
}
The call to draw is in my window class (this will place the partition in front of the job) but I need to order to be reversed without changing the order of the calls.
// Draw both Text and Block with transparency
DrawPartition part1 = new DrawPartition(Color.blue, 0, 0, 110, 100, "part1");
part1.setBounds(5, 5, 110, 100);
snapPanel.add(part1);
DrawJob job1 = new DrawJob(Color.green, 0, 0, 110, 100, "Job 1");
job1.setBounds(5, 15, 110, 100);
snapPanel.add(job1);
Is there some reason you can't do this?
// Draw both Text and Block with transparency
DrawPartition part1 = new DrawPartition(Color.blue, 0, 0, 110, 100, "part1");
part1.setBounds(5, 5, 110, 100);
DrawJob job1 = new DrawJob(Color.green, 0, 0, 110, 100, "Job 1");
job1.setBounds(5, 15, 110, 100);
snapPanel.add(job1);
snapPanel.add(part1);
A more general answer would be to add a z component to each of your rectangles. Then you can loop through your rectangles in the paintComponent method, drawing them in z order.