The following grid of buttons is defined as :
JButton button_x = new RoundButton();
where RoundButton is defined as :
public class RoundButton extends JButton {
public RoundButton(String label) {
super(label);
this.setContentAreaFilled(false);
Dimension size = this.getPreferredSize();
size.height = size.width = Math.max(size.height, size.width);
this.setPreferredSize(size);
}
#Override
protected void paintComponent(Graphics g) {
if(!GameState.getIfComplete()) { // If the game is not complete or has just started
this.setBorder(null);
g.setColor(Color.BLACK);
g.fillRect(0, 0, this.getSize().width, this.getSize().height);
if(this.getModel().isArmed()) {
g.setColor(Color.RED);
}else {
g.setColor(Color.GREEN);
}
g.fillOval(0,0,this.getSize().width-1,this.getSize().height-1);
super.paintComponent(g);
}else {
this.setBorder(null);
g.setColor(Color.BLACK);
g.fillRect(0, 0, this.getSize().width, this.getSize().height);
g.setColor(Color.WHITE);
g.fillOval(0,0,this.getSize().width-1,this.getSize().height-1);
super.paintComponent(g);
}
}
}
Currently all the buttons are painted in green, but on a certain condition I want to paint particular buttons in white (which is the code in the else part).For instance when !GameState.getIfComplete() returns false I want to paint the buttons in the first column in white. So I call repaint as :
buttons[0].repaint();
buttons[3].repaint();
buttons[6].repaint();
But this doesn't work ! With the first column some other buttons are also painted in white. Why is that ?
What is wrong with the call ? How do I paint a particular button ?
The problem is the reliance on the GameState, ALL your round buttons use the same logic to paint themselves, that is, when the game is completed, they will all be painted WHITE
Instead, you should rely on the properties of the button. Set it up so that the colors are actually derived from the button itself.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridLayout;
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.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class BadButton01 {
public static void main(String[] args) {
new BadButton01();
}
public BadButton01() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class GameState {
private static boolean isComplete;
public static boolean getIfComplete() {
return isComplete;
}
public static void setComplete(boolean value) {
isComplete = value;
}
}
public class TestPane extends JPanel {
private RoundButton[] btns = new RoundButton[]
{
new RoundButton("1"),
new RoundButton("2"),
new RoundButton("3"),
new RoundButton("4"),
new RoundButton("5"),
new RoundButton("6"),
new RoundButton("7"),
new RoundButton("8"),
new RoundButton("9")
};
public TestPane() {
setLayout(new GridLayout(3, 3));
for (RoundButton btn : btns) {
add(btn);
}
btns[0].addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
GameState.setComplete(true);
btns[0].setBackground(Color.WHITE);
btns[1].setBackground(Color.WHITE);
btns[2].setBackground(Color.WHITE);
repaint();
}
});
}
}
public class RoundButton extends JButton {
public RoundButton(String label) {
super(label);
this.setContentAreaFilled(false);
setBorderPainted(false);
setFocusPainted(false);
setOpaque(false);
Dimension size = this.getPreferredSize();
size.height = size.width = Math.max(size.height, size.width);
this.setPreferredSize(size);
setBackground(Color.GREEN);
}
#Override
protected void paintComponent(Graphics g) {
// if (!GameState.getIfComplete()) { // If the game is not complete or has just started
// this.setBorder(null);
// g.setColor(Color.BLACK);
// g.fillRect(0, 0, this.getSize().width, this.getSize().height);
if (this.getModel().isArmed()) {
g.setColor(Color.RED);
} else {
// g.setColor(Color.GREEN);
g.setColor(getBackground());
}
// } else {
// this.setBorder(null);
// g.setColor(Color.BLACK);
// g.fillRect(0, 0, this.getSize().width, this.getSize().height);
// g.setColor(Color.WHITE);
// g.fillOval(0, 0, this.getSize().width - 1, this.getSize().height - 1);
// g.setColor(getBackground());
// }
g.fillOval(0, 0, this.getSize().width - 1, this.getSize().height - 1);
super.paintComponent(g);
}
}
}
Related
I am having trouble drawing on a translucent frame. When the "alphaValue" is 255 everything works as expected. But I need a translucent frame. I created a small test class below that demonstrates the problem. As you can see the "MIDDLE" rectangle appears all the time. But the "DRAW" rectangle only appears when "alphaValue" is 255. When it is <=254 you can see via print lines that the method is still called, but the image does not appear to refresh. Thank you in advance for any help.
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class TransparencyTest {
private static Point startPoint = new Point();
private static Point endPoint = new Point();
public static void main(String[] args) {
new TransparencyTest().test();
}
#SuppressWarnings("serial")
private void test() {
int alphaValue = 255;
Frame myFrame = new Frame();
myFrame.setUndecorated(true);
myFrame.setBackground(new Color(0, 0, 0, alphaValue));
myFrame.setSize(800, 800);
Panel myPanel = new Panel() {
public void paint(Graphics g) {
super.paint(g);
System.out.println("PAINT");
g.setColor(new Color(255, 0, 0, 255));
if(startPoint.equals(new Point())) {
System.out.println("MIDDLE");
g.drawRect(200, 200, 400, 400);
}
else {
System.out.println("DRAW");
g.drawRect(
(int)Math.min(startPoint.getX(), endPoint.getX()),
(int)Math.min(startPoint.getY(), endPoint.getY()),
(int)Math.abs(startPoint.getX() - endPoint.getX()),
(int)Math.abs(startPoint.getY() - endPoint.getY())
);
}
}
};
myFrame.add(myPanel);
MouseAdapter myMouseAdapter = new MouseAdapter() {
public void mousePressed(MouseEvent e) {
startPoint = e.getPoint();
}
public void mouseDragged(MouseEvent e) {
endPoint = e.getPoint();
myPanel.repaint();
}
};
myPanel.addMouseListener(myMouseAdapter);
myPanel.addMouseMotionListener(myMouseAdapter);
myFrame.setVisible(true);
}
}
AWT components don't have a concept of transparency in of themselves, they are always opaque.
You have use a JPanel, which you use setOpaque to control the opacity (on or off) with. This will allow the panel to become see through and you should then be able to see the alpha affect applied directly to the frame...
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TransparencyTest {
private static Point startPoint = new Point();
private static Point endPoint = new Point();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
new TransparencyTest().test();
}
});
}
#SuppressWarnings("serial")
private void test() {
int alphaValue = 128;
JFrame myFrame = new JFrame();
myFrame.setUndecorated(true);
myFrame.setBackground(new Color(0, 0, 0, alphaValue));
// myFrame.setOpacity(0.1f);
myFrame.setSize(800, 800);
myFrame.setLocation(100, 100);
JPanel myPanel = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("PAINT");
g.setColor(new Color(255, 0, 0, 255));
if (startPoint.equals(new Point())) {
System.out.println("MIDDLE");
g.drawRect(200, 200, 400, 400);
} else {
System.out.println("DRAW");
g.drawRect(
(int) Math.min(startPoint.getX(), endPoint.getX()),
(int) Math.min(startPoint.getY(), endPoint.getY()),
(int) Math.abs(startPoint.getX() - endPoint.getX()),
(int) Math.abs(startPoint.getY() - endPoint.getY())
);
}
}
};
myPanel.setOpaque(false);
myFrame.add(myPanel);
MouseAdapter myMouseAdapter = new MouseAdapter() {
public void mousePressed(MouseEvent e) {
startPoint = e.getPoint();
}
public void mouseDragged(MouseEvent e) {
endPoint = e.getPoint();
myPanel.repaint();
}
};
myPanel.addMouseListener(myMouseAdapter);
myPanel.addMouseMotionListener(myMouseAdapter);
myFrame.setVisible(true);
}
}
So basically I have some code I was working on a couple of days ago that is kind of like Paint, which allows you to essentially draw on the screen using the mouse. I kind of discovered this property by accident, and I realized that it is really inefficient and i'm wondering if there is a more practical way to do this. There isn't really any reason to give all of my code, but here are the important parts
private static void createAndShowGui() {
SimpleDraw mainPanel = new SimpleDraw();
MenuBar.createMenuBar();
JLabel label = new JLabel();
label.setText("Drawing prototype 0.0.1");
// label.setHorizontalTextPosition(JLabel.NORTH);
label.setFont(new Font("Serif", Font.BOLD, 20));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(),BoxLayout.PAGE_AXIS));
frame.setVisible(true);
frame.setJMenuBar(MenuBar.getMenuBar());
frame.setBackground(Color.WHITE);
frame.add(label);
The code block above sets up the jframe (the window)
#Override
public void mouseDragged(MouseEvent e)
{
// These console outputs are just so that I know what is happening
System.out.println("Event: MOUSE_DRAG");
System.out.println(e.getX());
System.out.println(e.getY());
System.out.println(e.getComponent());
System.out.println(e.getWhen());
System.out.println(e.getButton());
MOUSE_X = e.getX() - 5; //-5 so that the cursor represents the center of the square, not the top left corner.
MOUSE_Y = e.getY() - 5; //^
rect = new Rectangle(MOUSE_X, MOUSE_Y, 10, 10 ); //This doesn't ever come into action.
repaint();
}
The code above pretty much just sets the MOUSE_X and MOUSE_Y variables and the repaint(); method
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
if (rect != null) {
if (!colorChoice.equals("Default"))
{
g2.setColor(Color.BLACK);
}
switch(colorChoice) {
case "GRAY":
g2.setColor(Color.GRAY);
break;
case "CYAN":
g2.setColor(Color.CYAN);
break;
case "BLUE":
g2.setColor(Color.BLUE);
break;
case "RED":
g2.setColor(Color.RED);
break;
case "PINK":
g2.setColor(Color.PINK);
break;
case "YELLOW":
g2.setColor(Color.YELLOW);
break;
case "GREEN":
g2.setColor(Color.GREEN);
break;
case "PURPLE":
g2.setColor(Color.MAGENTA);
break;
case "RESET":
g2.setColor(Color.WHITE);
case "WHITE":
g2.setColor(Color.WHITE);
}
g2.fillRect(MOUSE_X, MOUSE_Y, 15, 15);
if (colorChoice.equals("RESET"))
resetColorOnCursor();
}
}
public static void clearBoard()
{
tempColor = colorChoice;
setColorChoice("RESET");
frame.repaint();
}
public static void resetColorOnCursor()
{
setColorChoice(tempColor);
}
This is the thing I came across accidentally. What I was trying to do when I found this out was basically make a square follow your cursor whenever you moved your mouse. But I forgot to type the code part paintComponent(g);, which turns this program into the thing that I originally intended. The bottom parts of this are essentially how I would clear the board. I'm 100% sure that this isn't the proper way to clear/reset a frame like this, but I couldn't find another way. If anyone has any tips or better methods to use to do this properly I would be very appreciative. Thanks! :D
You're current approach is basically breaking the requirements of the paint chain, by not calling super.paintComponent. The paintComponent method does a set of operations, which you are not taking over and which could result in some very weird paint artifacts which are difficult to replicate consistently.
Graphics is a shared resource, so the Graphics context which was used to paint some other control will be the same which is used to paint your component, unless you are "cleaning" the context before hand, what was previously painted to the context will remain (which is why you code currently "seems" to work).
Instead, you should use a MouseListener to define a anchor point, which represents the point at which the mouse was pressed and then use the MouseMotionListener to define the extent of the selection area, for example...
import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SelectExample {
public static void main(String[] args) {
new SelectExample();
}
public SelectExample() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private Rectangle selection;
public TestPane() {
MouseAdapter ma = new MouseAdapter() {
private Point clickPoint;
#Override
public void mousePressed(MouseEvent e) {
clickPoint = e.getPoint();
selection = null;
}
#Override
public void mouseDragged(MouseEvent e) {
Point dragPoint = e.getPoint();
int x = Math.min(clickPoint.x, dragPoint.x);
int y = Math.min(clickPoint.y, dragPoint.y);
int width = Math.max(clickPoint.x, dragPoint.x) - x;
int height = Math.max(clickPoint.y, dragPoint.y) - y;
if (selection == null) {
selection = new Rectangle(x, y, width, height);
} else {
selection.setBounds(x, y, width, height);
}
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
selection = null;
repaint();
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (selection != null) {
g.setColor(UIManager.getColor("List.selectionBackground"));
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.fill(selection);
g2d.dispose();
g2d = (Graphics2D) g.create();
g2d.draw(selection);
g2d.dispose();
}
}
}
}
Just to highlight the issue you will face if you continue to violate the requirements of the paintComponent method, this is what happens when I don't call super.paintComponent
I simply added two JButton's to the JFrame (so not even directly to the panel). paintComponent does a series of important jobs, which you neglected to perform, which is going to cause more problems and issues.
Free form line example...
A free form line is actually a illusion, it's a series of (small) lines drawn between a series of points, the reason for this is because the MouseListener won't report every mouse position it moves across, depending on the speed the mouse is moved, you might get lots of call backs or a few.
So, instead of drawing to just draw the points, we store the points in a List and draw lines between them, for example...
import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FreeFormLines {
public static void main(String[] args) {
new FreeFormLines();
}
public FreeFormLines() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private List<List<Point>> points;
public TestPane() {
points = new ArrayList<>(25);
MouseAdapter ma = new MouseAdapter() {
private List<Point> currentPath;
#Override
public void mousePressed(MouseEvent e) {
currentPath = new ArrayList<>(25);
currentPath.add(e.getPoint());
points.add(currentPath);
}
#Override
public void mouseDragged(MouseEvent e) {
Point dragPoint = e.getPoint();
currentPath.add(dragPoint);
repaint();
}
#Override
public void mouseReleased(MouseEvent e) {
currentPath = null;
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (List<Point> path : points) {
Point from = null;
for (Point p : path) {
if (from != null) {
g2d.drawLine(from.x, from.y, p.x, p.y);
}
from = p;
}
}
g2d.dispose();
}
}
}
This is a simple example for a practical paint Application, where you can control and change the size and the Color of your drawing.
public class Main extends Application{
#Override
public void start(Stage stage){
try{
g = can.getGraphicsContext2D();
g.setStroke(Color.BLACK);
g.setLineWidth(1);
c.setValue(Color.BLACK);
c.setOnAction(e->{
g.setStroke(c.getValue());
});
sli.setMin(1);
sli.setMax(100);
sli.setShowTickLabels(true);
sli.setShowTickMarks(true);
sli.valueProperty().addListener(e->{
double val = sli.getValue();
String str = String.format("%.1f", val);
lab.setText(str);
g.setLineWidth(val);
});
gri.addRow(0, c, sli, lab);
gri.setHgap(20);
gri.setAlignement(Pos.TOP_CENTER);
gri.setPadding( new Insets( 20, 0, 0, 0));
scene.setOnMousePressed(e->{.
g.beginPath();
g.lineTo(e.getSceneX(), e.getSceneY());
g.stroke();
});
scene.setOnMoudrDragged(e->{.
g.lineTo(e.getSceneX(), e.getSceneY());
g.stroke();
});
pan.getChildren().addAll(can, gri);
stage.setScene(scene);
stage.show();
}catch(Exception e){
e.printStrackTrace();
}
Canvas can = new Canvas(760, 490);
GraphicsContext g ;
ColorPicker c = new ColorPicker();
Slider sli = new Slider();
Label lab = new Label("1.0");
GridPane gri = new GridPane();
StackPane pan = new StackPane();
Scene scene = new Scene(pan, 760, 490);
public static void main (String [] args){
launch(args);
}
}
Or we can try drawing for only java code , I think it's so easy and powerful.
package drawingbymouse;
import java.awt.*;
import java.awt.event.*;
public class DrawingByMouse extends Frame
implements MouseMotionListener{
DrawingByMouse(){
addMouseMotionListener(this);
setSize(400, 400);
setLayout(null);
setVisible(true);
}
#Override
public void mouseDragged(MouseEvent e){
Graphics g = getGraphics();
g.setColor(Color.BLACK);
g.fillOval(e.getX(), e.getY(), 10, 10);
}
public void mouseMoved(MouseEvent e){
}
public static void main (String[]args){
new DrawingByMouse();
}
}
Trying to create a translucent paint view over my application.
So far, I have a few objects at play.
paintView //a wrapper class of a JPane.
gScrollPane // the area I'm trying to cover
layeredPane // the layered pane
Here's my code so far
layeredPane = new JLayeredPane();
paintView = new PaintView//rest of constructor
layeredPane.add(gScrollPane);
layeredPane.add(paintView.getComponent(), new Integer(5));
layeredPane.moveToFront(paintView.getComponent());
For some reason, it's just not working. getComponent returns a jPane. So that shouldn't be the issue. I've made the panel red and opaque for testing but no luck. Have I missed something in the documentation?
Edit:
So I'm not seeing the paintview on top of the gScrollPane
and getComponent just returns the internally wrapped pane. That's not really the issue though.
I think it has to do with the layout of the layered pane. (Flow at the moment)
Setting to box has the layers horizontally side by side (paintview left, gscrollpane right)
It's difficult to know exactly why you're having problems. It could be a paint issue, it could be a layout issue...
Don't forget, JLayeredPane has not layout manager by default. You could use one, but I simply overrode the doLayout method and "implemented" my own for the purpose of the example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
public class TestLayeredPane02 {
public static void main(String[] args) {
new TestLayeredPane02();
}
public TestLayeredPane02() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.setSize(600, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JLayeredPane {
private JTextPane tp;
public TestPane() {
tp = new JTextPane();
Reader reader = null;
try {
reader = new FileReader(new File("sometextfile.txt"));
tp.read(reader, "Help");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
reader.close();
} catch (Exception e) {
}
}
tp.setFont(UIManager.getFont("TextArea.font"));
JScrollPane scrollPane = new JScrollPane(tp);
scrollPane.setRowHeaderView(new LineNumberHeader(tp));
OverLayPane overLayPane = new OverLayPane();
add(scrollPane, new Integer(0));
add(overLayPane, new Integer(5));
moveToFront(overLayPane);
}
#Override
public void doLayout() {
for (Component comp : getComponents()) {
comp.setBounds(0, 0, getWidth(), getHeight());
}
}
}
public class OverLayPane extends JPanel {
public OverLayPane() {
setLayout(new BorderLayout());
try {
BufferedImage img = ImageIO.read(new File("/path/to/image.png"));
JLabel label = new JLabel(new ImageIcon(img.getScaledInstance(-1, 200, Image.SCALE_SMOOTH)));
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
add(label);
} catch (IOException ex) {
ex.printStackTrace();
}
setOpaque(false);
setBackground(new Color(255, 0, 0, 128));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(getBackground());
g2d.fill(new Rectangle(0, 0, getWidth(), getHeight()));
g2d.dispose();
}
}
public class LineNumberHeader extends JPanel {
private JTextPane field;
public LineNumberHeader(JTextPane field) {
this.field = field;
field.getDocument().addDocumentListener(new DocumentListener() {
#Override
public void insertUpdate(DocumentEvent e) {
revalidate();
repaint();
}
#Override
public void removeUpdate(DocumentEvent e) {
revalidate();
repaint();
}
#Override
public void changedUpdate(DocumentEvent e) {
revalidate();
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
int height = field.getPreferredSize().height;
Element root = field.getDocument().getDefaultRootElement();
int lineCount = root.getElementCount();
FontMetrics fm = getFontMetrics(getFont());
int width = fm.stringWidth(Integer.toString(lineCount)) + 4;
return new Dimension(width, height);
}
protected void drawLineNumber(Graphics2D g2d, int line, Element element) {
int startIndex = element.getStartOffset();
FontMetrics fm = g2d.getFontMetrics();
String strLine = Integer.toString(line);
try {
Rectangle rect = field.modelToView(startIndex);
int strWidth = fm.stringWidth(strLine);
g2d.drawString(strLine, getWidth() - 2 - strWidth, rect.y + fm.getAscent());
} catch (BadLocationException ex) {
ex.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Element root = field.getDocument().getDefaultRootElement();
drawLineNumber(g2d, 1, root);
for (int index = 0; index < root.getElementCount(); index++) {
Element element = root.getElement(index);
drawLineNumber(g2d, index + 1, element);
}
g2d.dispose();
}
}
}
I have a Java paint program, and I've got two problems to do with it. Both problems are relatively simple, and just regard how the mouse input is handled and how the image uses colors. Here's a photo of the app:
So here's my first problem:
As you can see, by the look of the app, there's a spray of dots on the paint area. Each of those dots is a mouseclick. The program does not recognize when a user is holding down the mouse button, so you have to click individually.
This is obviously counterproductive, user-unfriendly and unacceptable. Now, how I fix this, I'm not sure. I've tried using a permanent while (true) loop, but that does not work. How do I make it so that instead of having to click every time, each time the mouse is held down it sprays out dots?
The second problem is the color of the dots. As you can see, at the bottom, there are color buttons. These function, but there is a problem: Whenever I change the color, all the dots currently on the screen change color. The color is run by a variable called currentColor which is run by the actionListeners controlled by all the color buttons on the bottom panel. How do I make sure that colors already placed on the screen are not affected anymore?
I believe that all the code that can be fixed for these two problems lies in my custom JPanel which is used for the program to paint on. I'll post the entire class below, and if you have any other questions, please let me know.
int xCord, yCord;
public class PaintPanel extends JPanel implements MouseListener {
// default serial whatever...
private static final long serialVersionUID = -6514297510194472060L;
public PaintPanel() {
addMouseListener(this);
}
ArrayList<Point> points = new ArrayList<Point>();
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (Point point : points) {
g.setColor(currentColor);
g.fillOval(point.x, point.y, 12, 12);
}
repaint();
}
#Override
public void mouseClicked(MouseEvent m) {
}
#Override
public void mouseEntered(MouseEvent m) {
}
#Override
public void mouseExited(MouseEvent m) {
}
#Override
public void mousePressed(MouseEvent m) {
if (paintPanel.contains(m.getPoint())) {
points.add(m.getPoint());
xCord = m.getX();
yCord = m.getY();
System.out.println("x: " + xCord + " y: " + yCord);
}
}
#Override
public void mouseReleased(MouseEvent m) {
}
}
Painting in Swing is destructive.
That is to say, when Swing requests that a repaint occur on a component, the component is expected to clear what ever was previously paint and update itself.
The problem with your color issue is that you only ever have a single color specified.
A possible solution would be to paint to backing buffer (like BufferedImage) instead of relying on paintComponent.
Instead of repainting all the dots each time paintComponent is called, you would simply paint the BufferedImage instead.
As to your issue with the mouse, you need to implement a MouseMotionListener, this will allow you to detect when the mouse is dragged across the surface, painting a trail of dots
Update with very BASIC example
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SimplePaint04 {
public static void main(String[] args) {
new SimplePaint04();
}
public SimplePaint04() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private PaintPane paintPane;
public TestPane() {
setLayout(new BorderLayout());
add((paintPane = new PaintPane()));
add(new ColorsPane(paintPane), BorderLayout.SOUTH);
}
}
public class ColorsPane extends JPanel {
public ColorsPane(PaintPane paintPane) {
add(new JButton(new ColorAction(paintPane, "Red", Color.RED)));
add(new JButton(new ColorAction(paintPane, "Green", Color.GREEN)));
add(new JButton(new ColorAction(paintPane, "Blue", Color.BLUE)));
}
public class ColorAction extends AbstractAction {
private PaintPane paintPane;
private Color color;
private ColorAction(PaintPane paintPane, String name, Color color) {
putValue(NAME, name);
this.paintPane = paintPane;
this.color = color;
}
#Override
public void actionPerformed(ActionEvent e) {
paintPane.setForeground(color);
}
}
}
public class PaintPane extends JPanel {
private BufferedImage background;
public PaintPane() {
setBackground(Color.WHITE);
setForeground(Color.BLACK);
MouseAdapter handler = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
drawDot(e.getPoint());
}
#Override
public void mouseDragged(MouseEvent e) {
drawDot(e.getPoint());
}
};
addMouseListener(handler);
addMouseMotionListener(handler);
}
protected void drawDot(Point p) {
if (background == null) {
updateBuffer();;
}
if (background != null) {
Graphics2D g2d = background.createGraphics();
g2d.setColor(getForeground());
g2d.fillOval(p.x - 5, p.y - 5, 10, 10);
g2d.dispose();
}
repaint();
}
#Override
public void invalidate() {
super.invalidate();
updateBuffer();
}
protected void updateBuffer() {
if (getWidth() > 0 && getHeight() > 0) {
BufferedImage newBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = newBuffer.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, getWidth(), getHeight());
if (background != null) {
g2d.drawImage(background, 0, 0, this);
}
g2d.dispose();
background = newBuffer;
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (background == null) {
updateBuffer();
}
g2d.drawImage(background, 0, 0, this);
g2d.dispose();
}
}
}
I need to create a program to draw shapes(user chooses with radio button), and whether or not the shape is filled(user chooses with check box). This is the code I have so far:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class SelectShape extends JFrame implements ItemListener{
private JRadioButton line = new JRadioButton("Line");
private JRadioButton rect = new JRadioButton("Rectangle");
private JRadioButton oval = new JRadioButton("Oval");
private JCheckBox fill = new JCheckBox("Filled");
private FigurePanel fp;
public static void main(String[] args) {
SelectShape frame = new SelectShape();
frame.setTitle("Select Shape");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setSize(400,400);
frame.setVisible(true);
}
public SelectShape() {
JPanel p1 = new JPanel();
p1.add(fp);
fp.setBackground(Color.WHITE);
p1.setSize(200,400);
JPanel p2 = new JPanel();
p2.setLayout(new FlowLayout());
p2.add(line);
p2.add(rect);
p2.add(oval);
p2.add(fill);
add(p2, "South");
line.addItemListener(this);
rect.addItemListener(this);
oval.addItemListener(this);
fill.addItemListener(this);
}
public void ItemStateChanged(ItemEvent e) {
if(rect.isSelected()) {
FigurePanel.dRect();
repaint();
}
else if(oval.isSelected()) {
FigurePanel.dOval();
repaint();
}
else if(line.isSelected()) {
FigurePanel.dLine();
repaint();
}
if(fill.isSelected()) {
FigurePanel.fill();
repaint();
}
else {
FigurePanel.erase();
repaint();
}
}
}
class FigurePanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
public void dLine(Graphics g) {
g.drawLine(10,10,160,10);
}
public void dRect(Graphics g) {
g.drawRect(10,10,150,50);
}
public void dOval(Graphics g) {
g.drawOval(10,10,150,50);
}
public void fill(Graphics g) {
g.setColor(Color.GREEN);
if(rect.isSelected()) {
g.fillRect(10,10,150,50);
}
else if(oval.isSelected()) {
g.fillOval(10,10,150,50);
}
}
public void erase(Graphics g) {
g.setColor(Color.WHITE);
if(rect.isSelected()) {
g.fillRect(10,10,150,50);
}
else if(oval.isSelected()) {
g.fillOval(10,10,150,50);
}
}
}
}
The errors I am getting are illegal start of expression and identifier expected. If I should approach this another way, please tell.
I think you need to go back to basics...
This won't work...
fp.setBackground("white");
Component#setBackground doesn't take a String as a parameter, it takes a Color
All your addItemListener calls arn't going to work, because you've not implement a ItemListener
I'm not sure what it is you hope to achieve by doing this...
#Override
fp.dRect();
But it won't work. #Override is used to indicate that a method was overridden by an ancestor, you are simply calling the method of FigurePanel
Java, like C and C++ is case sensitive;
There is no such class itemEvent...it's ItemEvent
public void ItemStateChanged(itemEvent e) {
There is no such class graphics, it's Graphics
public void paintComponent(graphics g) {
And I'm not even going to try and guess what it is you were hoping to achieve with the following...
public void paintComponent(graphics g) {
super.paintComponent(g);
dLine() {
g.drawLine(10, 10, 160, 10);
}
dRect() {
g.drawRect(10, 10, 150, 50);
}
dOval() {
g.drawOval(10, 10, 150, 50);
}
fill() {
g.setColor(Color.GREEN);
if (rect.isSelected()) {
g.fillRect(10, 10, 150, 50);
} else if (oval.isSelected()) {
g.fillOval(10, 10, 150, 50);
}
}
erase() {
g.setColor(Color.WHITE);
if (rect.isSelected()) {
g.fillRect(10, 10, 150, 50);
} else if (oval.isSelected()) {
g.fillOval(10, 10, 150, 50);
}
}
}
Java doesn't support "inline methods" (or what ever you want to call them) and no, making them methods would also not achieve what you are trying to do...
In fact the one thing you did very well, was to override paintComponent and call super.paintComponent...well done :D !
Updated
I would encourage you to have a read through...
The Java Trails, especially those covering the basics, especially those covering inheritance
Custom Painting
2D Graphics
Updated with possible running example
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import javax.swing.AbstractAction;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DrawShapes {
public static void main(String[] args) {
new DrawShapes();
}
public DrawShapes() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new DrawPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DrawPane extends JPanel {
public DrawPane() {
setLayout(new BorderLayout());
RenderPane rp = new RenderPane();
add(new ControlsPane(rp), BorderLayout.NORTH);
add(rp);
}
}
public class ControlsPane extends JPanel {
public ControlsPane(RenderPane rp) {
JRadioButton[] btns = new JRadioButton[4];
btns[0] = new JRadioButton(new LineAction(rp));
btns[1] = new JRadioButton(new RectangleAction(rp));
btns[2] = new JRadioButton(new OvalAction(rp));
btns[3] = new JRadioButton(new ClearAction(rp));
ButtonGroup bg = new ButtonGroup();
for (JRadioButton btn : btns) {
bg.add(btn);
add(btn);
}
}
}
public class RenderPane extends JPanel {
private Shape shape;
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public void setShape(Shape shape) {
this.shape = shape;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (shape != null) {
g2d.setColor(Color.RED);
g2d.draw(shape);
}
g2d.dispose();
}
}
public class LineAction extends AbstractRenderAction {
public LineAction(RenderPane renderPane) {
super(renderPane);
putValue(NAME, "Line");
}
#Override
public Shape getShape() {
return new Line2D.Float(0f, 0f, getRenderPane().getWidth(), getRenderPane().getHeight());
}
}
public class RectangleAction extends AbstractRenderAction {
public RectangleAction(RenderPane renderPane) {
super(renderPane);
putValue(NAME, "Rectangle");
}
#Override
public Shape getShape() {
return new Rectangle2D.Float(10, 10, getRenderPane().getWidth() - 20, getRenderPane().getHeight() - 20);
}
}
public class OvalAction extends AbstractRenderAction {
public OvalAction(RenderPane renderPane) {
super(renderPane);
putValue(NAME, "Oval");
}
#Override
public Shape getShape() {
float radius = Math.min(getRenderPane().getWidth() - 20, getRenderPane().getHeight() - 20);
return new Ellipse2D.Float(10, 10, radius, radius);
}
}
public class ClearAction extends AbstractRenderAction {
public ClearAction(RenderPane renderPane) {
super(renderPane);
putValue(NAME, "Clear");
}
#Override
public Shape getShape() {
return null;
}
}
public abstract class AbstractRenderAction extends AbstractAction {
private RenderPane renderPane;
public AbstractRenderAction(RenderPane renderPane) {
this.renderPane = renderPane;
}
public RenderPane getRenderPane() {
return renderPane;
}
public abstract Shape getShape();
#Override
public void actionPerformed(ActionEvent e) {
getRenderPane().setShape(getShape());
}
}
}
Well, the following is definitely not valid Java code:
dLine() {
g.drawLine(10,10,160,10);
}
The same applies to the following dRect, etc.
I'm not sure exactly what you're trying to achieve with that code. If it is to define a method called dLine, you would do the following instead:
public void dLine(Graphics g) {
g.drawLine(10, 10, 160, 10);
}
I also noticed the following code, which is not currently causing you problems, but it will:
public void ItemStateChanged(itemEvent e) {
This is not capitalized properly, so it will not compile, and you're also not listening to any events, so it will never get called.
There are various other errors in the code, but this should get you started.