ok so i am trying to make a small java paint program but i am having trouble trying to get my buttons to work. I was able to get one color when i instantiated the MyPanel class, but i changed it around in an attempt to make use of my buttons. I basically have it setup to where each button activates a certain constructor in the MyPanel class and each constructor activates the appropriate methods to change the colors so I can draw. Im really new to programming so any advice you guys could give me would be much appreciated. I also have an extra class that is instantiated in the MyPanel class which i didnt bother putting in because i know the problem isnt in there. All the Red class does is set the color
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseMotionAdapter;
public class Driver
{
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable()
{
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
SwingUtilities.isEventDispatchThread();
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton red = new JButton("red");
JButton blue = new JButton("blue");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setVisible(true);
frame.pack();
frame.setSize(1000,1000);
panel.add(red);
panel.add(blue);
blue.addActionListener( new Action() );
red.addActionListener( new Action() );
}
}//end driver class
public class Action implements ActionListener
{
public void actionPerformed( ActionEvent e )
{
MyPanel d = new MyPanel();
}
}//end Action
public class MyPanel extends JPanel
{
private int xCoord = 50;
private int yCoord = 50;
private int squareW = 20;
private int squareH = 20;
Red red = new Red();
public MyPanel()
{
setBorder(BorderFactory.createLineBorder(Color.yellow));
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
moveSquarer(e.getX(),e.getY());
}
});
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
moveSquarer(e.getX(),e.getY());
}
});
}
private void moveSquare(int x, int y)
{
if ((xCoord != x) || (yCoord!= y)) {
repaint(xCoord,yCoord,squareW+1,squareH+1);
red.setX(x);
red.setY(y);
repaint(red.getX(),red.getY(),red.getWidth()+1,red.getLength()+1);
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("hi",10,20);
red.paintSquare(g);
} //end MyPanel
I basically have it setup to where each button activates a certain
constructor in the MyPanel class and each constructor activates the
appropriate methods to change the colors so I can draw.
I can't see it since your ActionListener is the same for both buttons:
private static void createAndShowGUI() {
...
blue.addActionListener( new Action() );
red.addActionListener( new Action() );
...
}
public class Action implements ActionListener {
#Override
public void actionPerformed( ActionEvent e ) {
MyPanel d = new MyPanel();
}
}
This method doesn't even add this new panel to the frame so it will never be visible.
Also what is this object?
Red red = new Red();
Suggested approach
You may follow this suggested tips to achieve your goal:
Provide MyClass with a method to set the desired color.
Add an instance of this panel (or many as needed) to the frame when you initialize your GUI. Note: this/these may be added dinamically but you need to follow the hints about adding components to a displayed container described here
Use action listener to set the panel color as you whish.
For instance:
public class MyPanel extends JPanel {
private Color color = Color.red;
// this color should be used within paintComponent() method
public void setColor(Color newColor) {
color = newColor;
repaint();
}
...
}
Related
I am actually trying to create a JPanel, containing a bunch of ui elements for the user to manipulate the application. This panel is placed on top of Java3D scene. Therefore, I wanted the background of this JPanel to be transparent. Neither panel.setBackground(new Color(0,0,0,0)) nor popupPanel.setOpaque(false) nor both calls made the panel background transparent. So I decided to sub-class JPanel and play with paintComponent. No effect. Then I tried paint. Nothing. Then I got confused. So I overwrote literally every method I know of, related to painting a JPanel and left each method body blanc (see below). When I run the application, I still get the panel. How can that be? I placed some System.out.println to be sure that the class is the right one, and is called. It is the right one. Despite all this missing code, the only difference to a normal JPanel is that the button is only painted if the mouse enters the button bounds. What am I missing?
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JPanel;
public class TransparentPanel extends JPanel {
protected Color bg = new Color(0,0,0,0);
public TransparentPanel() {
super();
setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) { }
#Override
public void paint(Graphics g) {
System.out.println(System.getProperty("java.vendor"));
System.out.println(System.getProperty("java.version"));
for(Component c: getComponents()) {
System.out.println(c.toString());
}
}
#Override
public void repaint(Rectangle r) {}
#Override
public void repaint(long tm,int x,int y,int width, int height) {}
#Override
protected void paintChildren(Graphics g) {}
#Override
protected void paintBorder(Graphics g) {}
#Override
public void paintImmediately(int x,int y,int width, int height) {}
#Override
public void paintImmediately(Rectangle r) {}
}
and
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
public class OverlayoutTest extends JFrame {
public OverlayoutTest() {
super("Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(new Dimension(400, 300));
add(createPanel());
setLocationRelativeTo(null);
setVisible(true);
}
private JPanel createPanel() {
JPanel mainPanel = new JPanel(){
#Override
public boolean isOptimizedDrawingEnabled() {
return false;
}
};
mainPanel.setLayout(new OverlayLayout(mainPanel));
JComponent popupPanel = createPopupPanel();
popupPanel.setAlignmentX(1.0f);
popupPanel.setAlignmentY(0.0f);
mainPanel.add(popupPanel);
SpatialView view = new SpatialView(null); // A class extending JPanel containing a Java3D Canvas3D in a BorderLayout
mainPanel.add(view);
view.addScaledPlanetModel();
return mainPanel;
}
private JComponent createPopupPanel() {
TransparentPanel popupPanel = new TransparentPanel();
// popupPanel.setBackground(new Color(0,0,0,0));
// popupPanel.setOpaque(false);
popupPanel.setMaximumSize(new Dimension(250, 300));
JButton button = new JButton("HI there!"); // the button does nothing but is nice to spot
button.setForeground(Color.WHITE);
popupPanel.add(button );
return popupPanel;
}
public static void main(String[] args) {
new OverlayoutTest();
}
}
I am using OpenJDK version "11" 2018-09-25, build 11+28 and Java3D 1.7.0
I'm not sure how java graphics work. It seems
to be executing something itself so I am trying to break it
down.
I'm trying to create the blank JPanel and then only draw to it
once the JButton has been clicked but it doesn't work
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
public class testGui {
// global ======================================================================
static gui gc_gui;
// main ========================================================================
public static void main(String[] args) {
gc_gui = new gui();
gc_gui.cv_frame.setVisible(true);
listeners();
}
// action listeners ============================================================
public static void listeners() {
ActionListener ll_square = new ActionListener() {
public void actionPerformed(ActionEvent event) {
gc_gui.cv_content.draw(graphic);
}
};
gc_gui.cv_button.addActionListener(ll_square);
}
// gui =========================================================================
public static class gui {
JFrame cv_frame;
JButton cv_button;
content cv_content;
public gui() {
cv_frame = new JFrame();
cv_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cv_frame.setTitle("Test GUI");
cv_frame.setSize(600, 400);
cv_frame.setLayout(new FlowLayout());
cv_button = new JButton("Square");
cv_content = new content();
cv_content.setBackground(Color.BLACK);
cv_content.setPreferredSize(new Dimension(500, 300));
cv_frame.add(cv_button);
cv_frame.add(cv_content);
}
}
// content =====================================================================
public static class content extends JPanel {
public void paint(Graphics graphic) {
super.paint(graphic);
}
public void update() {
super.repaint();
}
public void draw(Graphics graphic) {
Graphics2D graphic2D = (Graphics2D) graphic;
graphic2D.setPaint(Color.RED);
graphic2D.fillRect(10, 10, 100, 100);
}
}
}
I create the content JPanel without the draw function being
called and then I try to call it using my ActionListener
although it is crashing because of the graphic variable.
What is the correct way to use the java graphics utility?
UPDATE
Maybe I'm not asking this question right but it is possible to
create a blank image.
Then draw additional images to that images (squares) after a button
has been clicked?
not just updating the dimensions using global variables but generating
new images to that existing image
but it is possible to create a blank image. Then draw additional images to that images (squares) after a button has been clicked?
Check out Custom Painting Approaches for two common ways to do painting.
The example allows you to draws Rectangles with the mouse. In your case the logic will be simpler as you would just invoke the addRectangle(...) method when you click a button. Of course you need to set the size/location of the Rectangle somehow.
import java.awt.Color;
import java.awt.Graphics;
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.border.LineBorder;
public class TestGui {
public static Content content;
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Test GUI");
frame.setSize(429, 385);
frame.getContentPane().setLayout(null);
JButton cv_button = new JButton("Square");
cv_button.setBounds(10, 159, 70, 23);
frame.getContentPane().add(cv_button);
cv_button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Content.isToDraw = true;
content.paintImmediately(content.getBounds());
Content.isToDraw = false;
}
});
JButton cv_buttonClear = new JButton("Clear");
cv_buttonClear.setBounds(10, 179, 70, 23);
frame.getContentPane().add(cv_buttonClear);
cv_buttonClear.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
content.paintImmediately(content.getBounds());
}
});
content = new Content();
content.setBorder(new LineBorder(new Color(0, 0, 0)));
content.setBounds(87, 11, 287, 312);
frame.getContentPane().add(content);
frame.setVisible(true);
}
}
class Content extends JPanel {
public static Boolean isToDraw = false;
public void paintComponent(Graphics arg0) {
if (isToDraw) {
arg0.setColor(Color.RED);
arg0.fillRect(0, 0, getWidth(), getHeight());
} else {
super.paintComponent(arg0);
}
}
}
This question already has answers here:
How to draw in JPanel? (Swing/graphics Java)
(4 answers)
Closed 9 years ago.
Hi im making a project for my studies and im new in java. I need to do a game - Arkanoid. What i wanted to do is a game manu with 2 buttons "New game" and "Quit". Someone from stackoverflow.com rebuild my menu code but it still doesnt work :( After clicking a "New Game" im getting blank frame :(. Probably becouse of Gra constructor. How constructor of Gra need to look like to make it works with my menu code.
Here is the code (i will paste all Arkanoid class code and most important parts of Gra class):
Arkanoid class:
package arkanoid;
import javax.swing.*;
import java.awt.event.*;
public class Arkanoid extends JFrame
{
private static final long serialVersionUID = 5647459635833443178L;
public Arkanoid() {
super("Arkanoid");
setSize(500,400);
setTitle("Arkanoid BETA");
setLocationRelativeTo(null);
setResizable(false);
final JPanel panel = new JPanel();
setContentPane(panel);
panel.add(new JButton(new AbstractAction("New game") {
public void actionPerformed (ActionEvent e) {
panel.removeAll();
panel.add(new Gra()); //constructor of Gra need to return some Panel i think but i dont know how to do that
panel.revalidate();
panel.repaint();
}
}));
panel.add(new JButton(new AbstractAction("Quit") {
public void actionPerformed (ActionEvent e) {
Arkanoid.this.setVisible(false);
}
}));
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Arkanoid frame = new Arkanoid();
frame.setVisible(true);
}
});
}
}
Gra class:
package arkanoid;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JOptionPane;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class Gra extends JPanel
{
/*some not important variables*/
Pilka pilka;
Paletka paletka;
Cegla cegla_tab[];
Serce serce_tab[];
Timer timer;
public Gra()
{
addKeyListener(new TAdapter());
setFocusable(true);
cegla_tab = new Cegla[liczba_cegiel];
serce_tab = new Serce[max_zycia];
//setDoubleBuffered(true);
timer = new Timer();
timer.scheduleAtFixedRate(new ScheduleTask(), 1000, 10);
}
public void addNotify()
{
super.addNotify();
start_gry();
}
public void start_gry()
{
pilka = new Pilka();
paletka = new Paletka();
/* painting a bricks and lifes for game start */
}
public void koniec_gry() //end of a game
{
czas_konca = System.currentTimeMillis();
gra = 3;
timer.cancel();
}
public void paint(Graphics g)
{
super.paint(g);
//repaiting ball positions, bricks and paddle
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
private class TAdapter extends KeyAdapter
{
public void keyReleased(KeyEvent e)
{
paletka.klawisz_puszczony(e);
}
public void keyPressed(KeyEvent e)
{
paletka.klawisz_wcisniety(e);
}
}
class ScheduleTask extends TimerTask
{
public void run()
{
if(paletka.czy_pausa()==false)
{
pilka.przesun();
paletka.przesun();
czy_zderzenie();
repaint();
}
}
}
public void czy_zderzenie()
{
//checking a collisions with bricks
}
}
You need to override paintComponent, not paint.
Also, Gra's constructor does return a JPanel. The constructor will return the object you're constructing, which in this case is a Gra, which is also a JPanel. This is polymorphism at work.
Oh, and as per the comment above, you really shouldn't be disposing of the graphics object.
When it is clicked on JLabel, I want to understand if the click was on "Icon part", or "Text part" of the JLabel, so that different action can be taken. Is there a clever way to do that? Or just I have to solve it relatively with the coordinates of the icon and text?
+1 to #aymeric comment.
What about having two different JLabels
However I do understand why you might be hesitating
negative: requires maintenance of 2 labels.
My clever (:P) solution to this is create your own abstract component - which accepts icon and text as parameters for constructor - by extending JPanel and than adding 2 JLabels to the JPanel, each label has its on MouseAdapter which calls abstract method xxxClicked() (thus any implementing class must override these methods).
Here is an example I made:
import java.awt.FlowLayout;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ImageIcon ii = null;
try {
//I dont remmend getScaledInstance just used it for speed of code writing
ii = new ImageIcon(ImageIO.read(new URL("http://www.candonetworking.com/java.gif")).getScaledInstance(32, 32, Image.SCALE_SMOOTH));
} catch (Exception ex) {
ex.printStackTrace();
}
MyLabel ml = new MyLabel(ii, "Something") {
#Override
void iconClicked() {
System.out.println("Icon clicked");
}
#Override
void textClicked() {
System.out.println("Text clicked");
}
};
frame.add(ml);
frame.pack();
frame.setVisible(true);
}
});
}
}
abstract class MyLabel extends JPanel {
JLabel iconLabel;
JLabel textLabel;
MouseAdapter iconMA;
MouseAdapter textMA;
public MyLabel(ImageIcon icon, String text) {
iconLabel = new JLabel(icon);
textLabel = new JLabel(text);
iconMA = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent me) {
super.mouseClicked(me);
iconClicked();
}
};
textMA = new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent me) {
super.mouseClicked(me);
textClicked();
}
};
iconLabel.addMouseListener(iconMA);
textLabel.addMouseListener(textMA);
add(iconLabel);
add(textLabel);
}
abstract void iconClicked();
abstract void textClicked();
public JLabel getIconLabel() {
return iconLabel;
}
public JLabel getTextLabel() {
return textLabel;
}
}
I can not access public method of my class MyPanel which extends JPanel. In MyPanel I previously had private method called moveSquare, but in order to make it work for external requests, I changed it to public, but it still do not work? How to make it working?
import javax.swing.SwingUtilities;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.BorderFactory;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseMotionAdapter;
public class mull {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JPanel p = createAndShowGUI();
iterate(p);
// "The method iterate(MyPanel) in the type mull is not applicable for the arguments (JPanel)"
}
});
}
private static JPanel createAndShowGUI() {
System.out.println("Created GUI on EDT? "+
SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Swing Paint Demo");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// how to grab link to this panel - in order to use it in iteration loop ?
MyPanel p = new MyPanel();
f.add(p);
// f.add(new MyPanel());
f.pack();
f.setVisible(true);
return p;
}
private static void iterate(JPanel p){
// the loop should change square position on each iteration
// how to implement ?
for (int i = 0; i < 999; i++){
((MyPanel) p).moveSquare(100 + i*10, 200 + i*10); // here is problem:
//"Cannot make a static reference to the non-static method moveSquare(int, int) from the type MyPanel"
}
}
}
class MyPanel extends JPanel {
private int squareX = 50;
private int squareY = 50;
private int squareW = 200;
private int squareH = 200;
public MyPanel() {
setBorder(BorderFactory.createLineBorder(Color.black));
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
moveSquare(e.getX(),e.getY());
}
});
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent e) {
moveSquare(e.getX(),e.getY());
}
});
}
// originally this method was private - in orger to access it within mull, it vas changed to public
public void moveSquare(int x, int y) {
int OFFSET = 1;
if ((squareX!=x) || (squareY!=y)) {
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
squareX=x;
squareY=y;
repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
}
}
public Dimension getPreferredSize() {
return new Dimension(900,700);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("This is my custom Panel!",10,20);
g.setColor(Color.RED);
g.fillRect(squareX,squareY,squareW,squareH);
g.setColor(Color.BLACK);
g.drawRect(squareX,squareY,squareW,squareH);
}
}
What does this syntax do ((MyPanel) p).moveSquare(100 + i*10, 200 + i*10); ?
How to paint custom shapes (ovals) in iterate(p)?
It doesn't seem like you're even calling iterate().
But in any case, your moveSquare method is not static, and thus expects a specific MyPanel instance to work on. So you'll probably want to keep a reference to your panel. Say, instead of f.add(new MyPanel()), you could use:
MyPanel p = new MyPanel();
f.add(p);
and then pass p to iterate and call p.moveSquare(100,200) in there.
You need to have a reference to MyPanel somewhere. In class mull add this at the top:
MyPanel myPanel = null;
Then when you add the panel do it like this:
myPanel = new MyPanel();
f.add(myPanel);
You can now reference myPanel from inside your class mull. Also classes should alwats start with a capital in Java (just because), so change it to Mull.