what I want to achieve is two buttons that enable the user choose the color ( black or red ) and then, depends on the color, draw red or black shape, e.g. rectangle on canvas.
I have a problem with relating MouseListeners connected with buttons to setting color of the graphics in Canvas class. Where should I define the color?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
class Can extends Canvas{
int x,y;
ArrayList<Point> points = new ArrayList<Point>();
Can(){
super();
addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent k){
x = k.getX();
y = k.getY();
points.add(new Point(x,y));
repaint();
}
});
}
public void paint(Graphics g){
int x2, y2;
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.black); //here is only black
for(Point p:points)
{
x2=(int)p.getX();
y2=(int)p.getY();
g2.fillRect(x2, y2, 10, 5);
}
}
}
class Win extends JFrame{
Win(String name){
super(name);
setLayout(new GridLayout());
JPanel p1 = new JPanel(new FlowLayout());
p1.setBackground(Color.cyan);
CheckboxGroup cg = new CheckboxGroup();
Checkbox red = new Checkbox("red", cg, true);
Checkbox black = new Checkbox("black", cg, false);
p1.add(red);
p1.add(black);
add(p1);
Can k = new Can();
add(k);
red.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent me){
System.out.println("Mouse click on red");
}
});
black.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent me){
System.out.println("Mouse click on black");
}
});
setSize(600, 400);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
public class ItM {
public static void main(String[] args) {
Win o = new Win("that's the window");
o.setVisible(true);
}
}
First of all you are using the Swing tag so your application should be using Swing components, not AWT components. Swing components start with "J", except for Canvas, where the Swing component is JPanel. You should then be overriding the paintComponent(...) method, not paint().
If you want to paint objects with different color then you have two options:
Paint directly to a BufferedImage. The then shape will be painted with the currently selected color
Paint from an ArrayList of object that contain information about the shape to be painted, including the size/location/color
For working examples of both approaches check out Custom Painting Approaches.
Related
I want to create a grid of squares in my Java Swing GUI. I need to toggle their state so I'm thinking a JToggleButton is appropriate for each of the squares.
The problem that I have is that I want to partially colour each toggle button according to given percentages. e.g. if 50% and 50% I want the left half of the button to be green and the right to be red. If 25%,25%,50% I'd need 3 colours. I also need to use the button Text field so hiding that isn't allowed in the solution.
Is it possible to do something like this with a JToggleButton? Is there a better element to use? Or how might I go about it?
I apologise for not posting my work so far but I can't find anything close to an example of this type of thing.
I want to end up with something like this where each square is a button.
You can construct a button with changeable 2-color background as required by overriding
paintComponent:
import java.awt.*;
import javax.swing.*;
public class TwoColorsButton extends JButton{
private final Color leftColor, rightColor;
private int percentOfLeftColor;
public TwoColorsButton(String text) {
this(text,Color.RED, Color.GREEN, 50);
}
public TwoColorsButton(String text, Color leftColor,Color rightColor, int percentOfLeftColor) {
super(text);
this.leftColor = leftColor;
this.rightColor = rightColor;
this.percentOfLeftColor = percentOfLeftColor;
//make button transparent
setOpaque(false);
setContentAreaFilled(false);
setBorderPainted(false);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
int leftWidth = getWidth() * percentOfLeftColor/100;
g2.setColor(leftColor);
g2.fillRect(0, 0, leftWidth , getHeight());
g2.setColor(rightColor);
g2.fillRect(leftWidth, 0, getWidth() -leftWidth, getHeight());
g2.setPaint(Color.BLACK);
super.paintComponent(g2); //button is transparent so super paints text only
g2.dispose();
}
public void setPercentOfLeftColor(int percentOfLeftColor) {
this.percentOfLeftColor = percentOfLeftColor;
repaint();
}
public int getPercentOfLeftColor() {
return percentOfLeftColor;
}
public static void main(String[] args) {
//run button test
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
JPanel topPanel = new JPanel();
TwoColorsButton twoColorBtn = new TwoColorsButton("Some Text");
topPanel.add(twoColorBtn);
frame.add(topPanel, BorderLayout.PAGE_START);
JPanel bottomPanel = new JPanel();
JButton runTestBtn = new JButton("Run test");
runTestBtn.addActionListener(e->{
runTestBtn.setEnabled(false);
new Timer(1000, e1 ->{
int percent = twoColorBtn.getPercentOfLeftColor() +25;
percent = percent > 100 ? 0 : percent;
twoColorBtn.setPercentOfLeftColor(percent);
}).start();
});
bottomPanel.add(runTestBtn);
frame.add(bottomPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setVisible(true);
}
}
The code can easily be modified to allow 3 colors, if needed.
(Test it online here)
(See a basic 3 colors toggle button here)
I am working on a simple object drawing program using Swing in Java.
My program simply should draw shapes according to buttons when clicked, and move any shapes with the mouse. I have four buttons which draw rectangle, circle and square on screen. So far I did managed to draw to shapes when you click on buttons. but i want to move the shapes on screen which it did not work out.
The problem is this: When I click on circle shape to drag it around with mouse, it clears all the screen and noting is on the screen.
And, is there a way to clean all the screen when I click on clear button?
Thank you?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PaintProject extends JComponent implements ActionListener,
MouseMotionListener {
private int CircleX=0;
private int CircleY=0;
private int RectX=100;
private int RectY=100;
private int SquareX=300;
private int SquareY=200;
public static void main(String[] args) {
JFrame frame = new JFrame("NEW PAINT PROGRAME!");
JButton CircleButton = new JButton("Circle");
CircleButton.setActionCommand("Circle");
JButton RectangleButton = new JButton("Rectangle");
RectangleButton.setActionCommand("Rectangle");
JButton SquareButton = new JButton("Square");
SquareButton.setActionCommand("Square");
PaintProject paint = new PaintProject();
CircleButton.addActionListener(paint);
RectangleButton.addActionListener(paint);
SquareButton.addActionListener(paint);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
frame.add(paint);
frame.add(CircleButton);
frame.add(RectangleButton);
frame.add(SquareButton);
frame.addMouseMotionListener(paint);
frame.pack();
frame.setVisible(true);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
private void drawCircle() {
Graphics g = this.getGraphics();
g.setColor(Color.red);
g.fillOval(CircleX, CircleY, 100, 100);
}
private void drawRectangle() {
Graphics g = this.getGraphics();
g.setColor(Color.green);
g.fillRect(RectX, RectY, 100, 300);
}
private void drawSquare() {
Graphics g = this.getGraphics();
g.setColor(Color.blue);
g.fillRect(SquareX, SquareY, 100, 100);
}
#Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("Circle")) {
drawCircle();
}
else if (command.equals("Rectangle")) {
drawRectangle();
}
else if (command.equals("Square")) {
drawSquare();
}
}
#Override
public void mouseDragged(MouseEvent e) {
CircleX=e.getX();
CircleY=e.getY();
repaint();
}
}
As noted here and here, getGraphics() is not how to perform custom painting in Swing. Instead, override paintComponent() to render the desired content. It looks like you want to drag shapes using the mouse. A basic approach to moving a selected object is shown here; substitute your fillXxx() invocation for the drawString() shown there. For multiple shapes, use a List<Shape>; the clear command then becomes simply List::clear. A complete example is cited here; it features moveable, selectable, resizable, colored nodes connected by edges.
I have the folowing custom JPanel and I have aded it to my frame using Netbeans GUI builder but the background won't change! I can see the circle, drawing with g.fillOval(). What's wrong?
public class Board extends JPanel{
private Player player;
public Board(){
setOpaque(false);
setBackground(Color.BLACK);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.red);
g.fillOval(player.getxCenter(), player.getyCenter(), player.getRadius(), player.getRadius());
}
public void updatePlayer(Player player){
this.player=player;
}
}
If your panel is 'not opaque' (transparent) you wont see your background color.
You have to call the super.paintComponent(); as well, to allow the Java API draw the original background. The super refers to the original JPanel code.
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.red);
g.fillOval(player.getxCenter(), player.getyCenter(), player.getRadius(), player.getRadius());
}
You need to create a new Jpanel object in the Board constructor.
for example
public Board(){
JPanel pane = new JPanel();
pane.setBackground(Color.ORANGE);// sets the background to orange
}
setOpaque(false);
CHANGED to
setOpaque(true);
I just tried a bare-bones implementation and it just works:
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame("Hello");
frame.setPreferredSize(new Dimension(200, 200));
frame.add(new Board());
frame.pack();
frame.setVisible(true);
}
}
public class Board extends JPanel {
private Player player = new Player();
public Board(){
setBackground(Color.BLACK);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.red);
g.fillOval(player.getCenter().x, player.getCenter().y,
player.getRadius(), player.getRadius());
}
}
public class Player {
private Point center = new Point(50, 50);
public Point getCenter() {
return center;
}
private int radius = 10;
public int getRadius() {
return radius;
}
}
In order to completely set the background to a given color :
1) set first the background color
2) call method "Clear(0,0,this.getWidth(),this.getHeight())" (width and height of the component paint area)
I think it is the basic procedure to set the background...
I've had the same problem.
Another usefull hint : if you want to draw BUT NOT in a specific zone (something like a mask or a "hole"), call the setClip() method of the graphics with the "hole" shape (any shape) and then call the Clear() method (background should previously be set to the "hole" color).
You can make more complicated clip zones by calling method clip() (any times you want) AFTER calling method setClip() to have intersections of clipping shapes.
I didn't find any method for unions or inversions of clip zones, only intersections, too bad...
Hope it helps
I have a poker game where I designed a nice pretty GUI that displays the cards and players. I did it all extending JPanel inside paint() with a lot of g2d.drawImage's and g2d.drawString()'s, with definite x and y locations.
My problem now is that I need to have a couple interactive buttons underneath it.. but whenever I try to add a JButton, it appears top and center. I've used setLocation(x, y) and setLayout(null) and everything I've seen in other replies, but none of them seem to match my need (Or at least I don't have a very well understanding of where to put it)
This is how my code is set up:
pokerserver.java
public class pokerserver extends JFrame {
public pokerserver() {
add(new drawing());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(720, 640);
setLocationRelativeTo(null);
setTitle("Poker HANGOUTS");
setResizable(false);
setVisible(true);
}
public static void main(String args[]) {
new pokerserver();
}
And then in drawing.class
public drawing() {
setFocusable(true);
setBackground(new Color(39,91,46));
setDoubleBuffered(true);
gameCards = new cards();
gameCards.shuffle();
for (int i = 0; i < 10; i++)
seats[i] = -1;
HQ = new HeadQuarters(this);
HQ.start();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
//All my UI code
}
My last attempt was trying to add
JButton button = new JButton("TEST");
add(button);
button.setLocation(10, 500);
at the end of public drawing(). I Keep seeing things on layout management, but it's not helping me -- mainly because I'm not sure how to implement it
Here's a screenshot to help visualize what I'm talking about->
http://i.imgur.com/ttvif.png
Trying to get the button underneath. Unless there's a way to add an ActionListener to a drawImage()?
For your main panel use a BorderLayout.
Then to the "CENTER" you can add your game panel with all your custom painting.
Then create a panel and add the buttons to it. Now you can add this panel to the NORTH of the main panel.
In other words you are not restricted to using a single panel.
Also, custom painting should be done in the paintComponent() method of your panel, NOT the paint() method.
I'm not really sure what you are after, but here are two interpretations.
I suspect you want the 1st one 'Buttons over custom painting', but as a user I'd prefer the 2nd, with 'Buttons below custom painting'.
import java.awt.image.*;
import java.awt.*;
import javax.swing.*;
class PaintPanel extends JPanel {
BufferedImage bg;
PaintPanel(LayoutManager2 layout) {
super(layout);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (bg==null) {
bg = new BufferedImage(500,500,BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = bg.createGraphics();
GradientPaint gp = new GradientPaint(
0,0,Color.RED,500,500,Color.BLUE);
g2.setPaint(gp);
g2.fillRect(0,0,500,500);
g2.dispose();
}
g.drawImage(bg,0,0,getWidth(),getHeight(),this);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JPanel buttons = new JPanel(
new FlowLayout(FlowLayout.CENTER));
buttons.setOpaque(false);
buttons.add(new JButton("Start"));
buttons.add(new JButton("Stop"));
PaintPanel pp = new PaintPanel(new BorderLayout());
pp.setPreferredSize(new Dimension(200,100));
pp.add(buttons, BorderLayout.SOUTH);
JOptionPane.showMessageDialog(null,pp);
JPanel gui = new JPanel(new BorderLayout());
gui.setBackground(Color.ORANGE);
gui.add(pp, BorderLayout.CENTER);
gui.add(buttons, BorderLayout.SOUTH);
JOptionPane.showMessageDialog(null,gui);
}
});
}
}
I'm creating a small game, you click buttons (up, down, left and right) to control a cat (represented by a rectangle) to chase a mouse (represented by another rectangle). Lame I know... anyway I'm using the mvc design pattern and I am having problems calling the repaint method from button listeners in the controller on the panel where the two rectangles are to be 'painted'. They paint successfully the first time but not any further time.
I've implemented the the paintComponent() method in two ways but both didn't work
Create a separate class that extends JPanel and does the paintComponent business, creating a new object of that class in the view and using it to paint the rectangles.
Creating a JPanel and writing the paintComponent stuff in the parenthesis of the new JPanel object.
and I've implemented the code to in the controller to repaint in two ways and both didn't work
Call a method from the view that returns the jpanel that uses the paintComponent method and calling repaint on it.
Creating a jpanel in the controller and assigning the panel from the view to it then calling repaint on that.
The code for the view and controller (which is long, sorry!) is below, it also includes the commented out stuff I couldn't get to work from the two methods to approaching the problem mentioned before...
View
/*
* gameView.java
*/
package game;
import java.awt.;
import java.awt.event.;
import javax.swing.*;
public class gameView extends JFrame{
//components
private JButton up = new JButton("Up");
private JButton down = new JButton("Down");
private JButton left = new JButton("Left");
private JButton right = new JButton("Right");
//panels
private JPanel content = new JPanel();
//boardPanel leftPanel = new boardPanel();
private Stroke drawingStroke = new BasicStroke(1);
private JPanel leftPanel = new JPanel(){
#Override
protected void paintComponent(Graphics g) {
super.paintComponents(g);
myPaint(g);
}
};
private JPanel rightPanel = new JPanel();
//model
private gameModel model;
//mouse and cat
private Rectangle cat;
private Rectangle mouse;
public void myPaint(Graphics g){
Graphics2D g1 = (Graphics2D)g;
Graphics2D g2 = (Graphics2D)g;
g1.setStroke(drawingStroke);
g1.draw(cat);
g1.setPaint(Color.yellow);
g1.fill(cat);
g2.setStroke(drawingStroke);
g2.draw(mouse);
g2.setPaint(Color.red);
g2.fill(mouse);
}
//constructor
public gameView(gameModel _model){
model = _model;
//cat and mouse
cat = new Rectangle(_model.getCatX(), _model.getCatY(), 10, 10);
mouse = new Rectangle(_model.getMouseX(), _model.getMouseY(), 10, 10);
//layout
content.setSize(500, 400);
content.setLayout(new GridLayout(0,2));
leftPanel.setSize(200, 200);
leftPanel.setBackground(Color.blue);
rightPanel.setSize(100, 400);
rightPanel.setLayout(new FlowLayout());
rightPanel.add(new JLabel("Controls"));
rightPanel.add(up);
rightPanel.add(down);
rightPanel.add(left);
rightPanel.add(right);
content.add(leftPanel);
content.add(rightPanel);
this.setSize(500, 400);
this.setContentPane(content);
this.setTitle("Cat & Mouse Game");
}
//returns the leftPanel to repaint in the controller
public JPanel getLeft(){
return leftPanel;
}
//listeners for buttons
public void addUpListener(ActionListener moveUp){
up.addActionListener(moveUp);
}
public void addDownListener(ActionListener moveDown){
down.addActionListener(moveDown);
}
public void addLeftListener(ActionListener moveLeft){
left.addActionListener(moveLeft);
}
public void addRightListener(ActionListener moveRight){
right.addActionListener(moveRight);
}
public void addCloseListener(WindowListener close){
this.addWindowListener(close);
}
//
public Rectangle getCat(){
return cat;
}
public Rectangle getMouse(){
return mouse;
}
//left side board panel
/*class boardPanel extends JPanel{
Stroke drawingStroke = new BasicStroke(1);
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g1 = (Graphics2D)g;
g1.setStroke(drawingStroke);
g1.draw(cat);
g1.setPaint(Color.yellow);
g1.fill(cat);
Graphics2D g2 = (Graphics2D)g;
g2.setStroke(drawingStroke);
g2.draw(mouse);
g2.setPaint(Color.red);
g2.fill(mouse);
}
}
public JPanel getLeft(){
return leftPanel;
}*/
}
Controller
/*
* gameController.java
*/
package game;
import java.awt.event.;
import javax.swing.;
public class gameController {
private gameModel model;
private gameView view;
private JPanel lp = new JPanel();
public gameController(gameModel _model, gameView _view){
model = _model;
view = _view;
lp=_view.getLeft();
//listeners
view.addUpListener(new UpListener());
view.addDownListener(new DownListener());
view.addLeftListener(new LeftListener());
view.addRightListener(new RightListener());
view.addCloseListener(
new WindowAdapter(){
public void windowClosing(WindowEvent we){
System.exit(0);
}
});
}
//DOWN
class DownListener implements ActionListener{
public void actionPerformed(ActionEvent e){
model.setCatY((model.getCatY()+10));
//do a random move for the mouse
//model.randomMove();
//view.getLeft().repaint();
lp.repaint();
System.out.println("x="+model.getCatX()+"y="+model.getCatY());
}
}
//LEFT
class LeftListener implements ActionListener{
public void actionPerformed(ActionEvent e){
model.setCatY((model.getCatY()-10));
//do a random move for the mouse
//model.randomMove();
//view.getLeft().repaint();
lp.repaint();
System.out.println("x="+model.getCatX()+"y="+model.getCatY());
}
}
//RIGHT
class RightListener implements ActionListener{
public void actionPerformed(ActionEvent e){
model.setCatY((model.getCatY()+10));
//do a random move for the mouse
//model.randomMove();
//view.getLeft().repaint();
lp.repaint();
System.out.println("x="+model.getCatX()+"y="+model.getCatY());
}
}
}
Looks like your button listeners update the model, but nothing actually updates the coordinates of the cat and mouse rectangles. They get their initial bounds from the model, but then are never updated.
The view should probably listen to the model to sync the cat and mouse's locations to the actual Rectangle objects.