I haven't been able to paint anything using an actionListener and paintComponent. I'm pretty sure I have the image name/path right. What am I doing wrong?
JApplet "Runner.java"
public class Runner extends JApplet{
public void init(){
World world = new World();
Container screen = this.getContentPane();
screen.add(world);
setSize(1200, 800);
repaint();
}
}
part of "World.java"
protected ArrayList<WorldObject> allStillObjects = new ArrayList<WorldObject>();
protected ArrayList<MovableObject> allMovableObjects = new ArrayList<MovableObject>();
protected ArrayList<WorldObject> screenStillObjects = new ArrayList<WorldObject>();
protected ArrayList<MovableObject> screenMovableObjects = new ArrayList<MovableObject>();
public World(){
this.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
this.setBackground(new Color(255,255,255));
this.setFocusable(true);
this.setFocusTraversalKeysEnabled(false);
this.addObject(new Card(this, "Two of Clubs", 0, 0, "card_two_c.png"));
timer = new Timer(60, new ClickListener());
timer.start();
}
public void addObject(WorldObject obj){
if(obj instanceof MovableObject){
this.allMovableObjects.add((MovableObject)obj);
if(isOnScreen(obj))
this.screenMovableObjects.add((MovableObject)obj);
}else{
this.allStillObjects.add(obj);
if(isOnScreen(obj))
this.screenStillObjects.add(obj);
}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
for(WorldObject obj : this.screenStillObjects)
obj.paintComponent(g);
for(MovableObject obj : this.screenMovableObjects)
obj.paintComponent(g);
}
private class ClickListener implements ActionListener{
public void actionPerformed(ActionEvent e){
repaint();
}
}
"ImageObject.java"
protected ImageIcon pic;
public ImageObject(World world, String name, int worldX, int worldY, String imageName){
super(world, name, worldX, worldY);
URL imgURL = getClass().getResource("images/" + imageName);
pic = new ImageIcon(imgURL);
this.width = pic.getIconWidth();
this.height = pic.getIconHeight();
}
public void paintComponent(Graphics g){
super.paintComponent(); //doesn't work with or without this line
pic.paintIcon(world, g, this.getWorldX(), this.getWorldY());
}
If there isn't enough of the code here I can add more
Edit: What's the best alternative to using a JApplet? World extends JPanel, WorldObject extends JPanel, ImageObject extends WorldObject, MovableObject extends ImageObject, Card extends MovableObject
I added the method for addObject above.
Well thank you for your answers, er, comments! They were very helpful. I went and changed my program so that it used a JFrame instead of a JApplet, and after a little fiddling, got an image to print. From there I was able to revert back to a JApplet and it works! Still not sure what my initial problem was though :|
Related
I have a draw class that extends JPanel and has a void method called drawing with repaint() in it.
public class draw extends JPanel {
public draw(int position_x, int position_y, int width, int height) {
positionx = position_x;
positiony = position_y;
this.width = width;
this.height = height;
}
public void drawing() {
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(positionx, positiony, width, height);
}
}
So, my intention is create a lot of this rectangles in a JPanel so they create a graphic bar.
public class coin_launcher {
public static void main(String[] args) {
JFrame frame = new JFrame("Coin Launcher");
frame.setVisible(true);
frame.setSize(1920, 1080);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
draw object = new draw(2,2,100,2);
frame.add(object);
object.drawing();
draw object2 = new draw(2,6,200,2);
frame.add(object2);
object2.drawing();
}
}
The problem is that when I call drawing() in both of the objects only one gets drawn.
If use the debugger its only the first one, if I dont, its only the second one. I need to make 100 bars but it literally repaints the JPanel every time, how can I add different draw class in one JPanel without erasing the others?
JFrame uses a BorderLayout by default, this means that only the last component added (to the default centre position) will be managed by the layout.
See BorderLayout for more details.
An immediate solution might be to use a different layout manager, but I would argue that's the wrong solution.
Instead, you should have ONE component, which is capable of paint multiple bars, based on the data available from a "model"
This decouples the source of the data from the presentation of the data, allowing to produce multiple different implementations of these, which shouldn't break the other.
In this case, the "view" shouldn't care how the data is obtained or marinated, only that it conforms to a specified contract, like wise the data doesn't care how its presented.
See Model-View-Controller for more details
This answer is a very basic and simplified example of
"you should have ONE component, which is capable of paint multiple
bars, based on the data available from a "model"
quoted from MadProgrammer's answer.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.Arrays;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CoinLauncher {
public static void main(String[] args) {
JFrame frame = new JFrame("Coin Launcher");
frame.setSize(920, 480);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//data to be painted. for better implementation use a model class that
//encapsulates the data
Rectangle[] bars = {
new Rectangle(2,2,100,2),
new Rectangle(2,6,200,2),
};
Draw object = new Draw(Arrays.asList(bars));
frame.add(object);
frame.setVisible(true);
}
}
class Draw extends JPanel {
private final List<Rectangle> bars;
Draw(List<Rectangle> bars) {
this.bars = bars;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
for(Rectangle bar : bars){
g.fillRect(bar.x, bar.y, bar.width, bar.height);
}
}
}
Implementing a model to encapsulate data need for the view, can be as simple as :
public class CoinLauncher {
public static void main(String[] args) {
JFrame frame = new JFrame("Coin Launcher");
frame.setSize(920, 480);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Model model = new Model();
model.addBar( new Rectangle(2,2,100,2) );
model.addBar( new Rectangle(2,6,200,2) );
Draw object = new Draw(model);
frame.add(object);
frame.setVisible(true);
}
}
class Draw extends JPanel {
private final List<Rectangle> bars;
Draw(Model model) {
bars = model.getBars();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
for(Rectangle bar : bars){
g.fillRect(bar.x, bar.y, bar.width, bar.height);
}
}
}
class Model {
private final List<Rectangle> bars;
Model(){
bars = new ArrayList<>();
}
void addBar(Rectangle rectangle){
bars.add(rectangle);
}
List<Rectangle> getBars() { return bars; }
}
I want the user of my program to be able to highlight an area on a JFrame to select a group of items on screen. The code I posted below works, but it is very choppy, which becomes quite an eyesore every single time the JFrame repaints. Here's an image of what I'm talking about: http://i1065.photobucket.com/albums/u400/mfgravesjr/choppy%20draw%20rectangle_zpsspqsqnyf.png
Maybe someone here has suggestions to improve my code?
This is the mouseDragged method in MouseMotionListener:
public void mouseDragged(MouseEvent me)
{
if(groupingTerr&&me.getSource()==background)
{
endPoint = MouseInfo.getPointerInfo().getLocation();
topLeftRect = new Point(Math.min(startPoint.x,endPoint.x),Math.min(startPoint.y,endPoint.y));
bottomRightRect = new Point(Math.max(startPoint.x,endPoint.x),Math.max(startPoint.y,endPoint.y));
for(Point p:map.territoryPoints)
{
if(p.x>topLeftRect.x&&p.x<bottomRightRect.x&&p.y>topLeftRect.y&&p.y<bottomRightRect.y)img.getGraphics().drawImage(selectedIco,p.x-selectedIco.getWidth()/2,p.y-selectedIco.getHeight()/2,null);
else img.getGraphics().drawImage(defaultIco,p.x-defaultIco.getWidth()/2,p.y-defaultIco.getHeight()/2,null);
}
background.repaint();
}
}
This is the private overridden JFrame class
private static class DrawableJFrame extends JFrame
{
#Override
public void paint(Graphics g)
{
super.paint(g);
g.setColor(new Color(0,0,0,100));
g.drawRect(topLeftRect.x,topLeftRect.y,bottomRightRect.x-topLeftRect.x,bottomRightRect.y-topLeftRect.y);
g.setColor(new Color(200,10,10,100));
g.fillRect(topLeftRect.x,topLeftRect.y,bottomRightRect.x-topLeftRect.x,bottomRightRect.y-topLeftRect.y);
}
}
The image is original artwork. Please do not use it.
I want to develop a Java Applet which shows visualization of Sorting. So I have written code like this...
public class SortNumbersGUI extends JApplet {
private static final long serialVersionUID = 1L;
List<Integer> randomList;
JLabel numberLabel;
JButton sortButton;
#Override
public void init() {
randomList = MyRandom.myRandom();
setSize(400, 400);
setLayout(new FlowLayout());
sortButton = new JButton("Sort");
sortButton.setBounds(50, 0, 50, 10);
sortButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Collections.sort(randomList);
removeAll();
repaint();
}
});
this.add(sortButton);
super.init();
}
#Override
public void paint(Graphics g) {
int y = 20;
for (Integer i : randomList) {
g.drawString(i.toString(), 0, y + 10);
g.fillRect(20, y, (i * 10) / 10, 5);
y = y + 20;
}
}
}
But, I am facing two problems here..
Sort button, which is JButton is not always visible. When i am placing mouse cursor over that sort button place then only it is appearing.
The results are overriding when I am calling repaint() method. As the bellow image
Result Image (As I don't have reputation I am pasting the image link.)
Please help me to solve this problem.
Thank you in Advance.
#Override
public void paint(Graphics g) {
// ..
Should be:
#Override
public void paint(Graphics g) {
super.paint(g); // paints **BG**, border etc.
// ..
Your problem is that you are overridding paint instead of paintComponent, and also you are not calling super.paint/Component (also a good practice, though possibly not 100% necessary here).
Because of how you've overridden paint(), you button is not getting automatically painted when the JApplet is painted
I am having trouble with a custom JPanel class I am using. I have a networked camera which I am receiving Images from using an HttpURLConnection and a JPEGDecoder. These images are then displayed using Graphic.drawImage. The camera is set to run at 1 fps for debugging purposes.
This JPanel class is include inside one JFrame, I also have another JFrame which contains a NASA WorldWind. When displaying the pictures from the Camera, my WorldWind map is unresponsive and will not repaint when resized. I believe it is because my paintComponent in the custom JPanel is being spammed.
I do not understand what is calling my JPanel's paintComponent so much, and preventing my WorldWind Frame to update.
A blurb of the custom JPanel class follows:
public class ActiCamera extends JPanel implements Runnable
{
private String mjpgURL;
private DataInputStream dis;
public ActiCamera(String ip)
{
mjpgURL = "http://" + ip + "/cgi-bin/cmd/encoder?GET_STREAM";
}
public void connect()
{
URL u = new URL(mjpgURL);
...
dis = new DataInputStream(from buffered input stream from HttpURLConnection);
}
public void start()
{
appletThread = new Thread(this);
appletThread.start();
}
public void run()
{
connect();
GetImages();
}
public void GetImages()
{
while(true)
{
//This blocks, executes at 1Hz
JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(dis);
image = decoder.decodeAsBufferedImage();
}
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if(image != null)
g.drawImage(image.getScaledInstance(getWidth(), getHeight(), Image.SCALE_DEFAULT), 0, 0, this);
}
public static void main(String [] args)
{
JFrame jframe = new JFrame();
ActiCamera my_panel = new ActiCamera("1.1.1.1");
my_panel.start();
jframe.getContentPane().add(my_panel);
jframe.setVisible(true);
}
}
Note, I do not call repaint() or force a paint anywhere. However, if I put a print out in my paint component class, it gets spammed at a much greater speed than 1 Hz. I am completely lost as to whats going on.
P.S. - I do realize I need a mutex between the paintComponent and the GetImages, they're being called from different threads, but I do not imagine that would cause the problem?
I found my answer, I had to change my paint component
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if(image != null)
g.drawImage(image, 0, 0, this);
}
The paintComponent in my earlier code snippet seems to have an implicit paintComponent call in it somewhere... perhaps in (getWidth() and getHeight() or getScaledInstance())
So I've tried to write some pixels using MemoryImageSource and display it in a frame. Here's the code:
public class ImageDraw extends JPanel {
Image img;
public void ImageDraw(){
//super();
int w=600;
int h=400;
int pixels[] = new int[w*h];
int i=0;
for(i=0;i<w*h;i++){
//pixels[i++]=0;
pixels[i]=255;
}
img = createImage(new MemoryImageSource(w,h,pixels,0,w));
}
public void paint(Graphics g){
g.drawImage(img, 0, 0, this);
}
}
and the main code
public class FuncTest {
public static void main(String[] args) {
JFrame frame = new JFrame("Display");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 400);
ImageDraw pan = new ImageDraw();
frame.getContentPane().add(pan);
frame.setVisible(true);
}
}
It just displays an empty frame. Why? My aim is to learn how to draw pixel by pixel, so this is only a test image I was drawing to see whether it works.
Thanks.
There are two issues with your code. First
public void ImageDraw() { ... }
is a method and not the constructor. The method is not called in your code at all. Change this line to
public ImageDraw() { ... }
without the void to make it the default constructor.
Second you need to set the alpha-value of your pixel data:
pixels[i] = 255 + 0xFF000000;
And two more points:
Please do not override paint(...) but paintComponent(...) instead.
Do not set the size of the JFrame but override the component's method getPreferredSize() and use frame.pack().