I was wondering what would be the best/easiest way to render my own graphics over an applet that has been loaded with:
public class Game {
public static Applet applet = null;
public static URLClassLoader classLoader = null;
public static void load() {
try {
classLoader = new URLClassLoader(new URL[]{Jar.getJar().toURL()});
applet = (Applet) classLoader.loadClass("com.funkypool.client.PoolApplet").newInstance();
applet.setSize(new Dimension(800, 600));
applet.setBackground(Color.BLACK);
applet.setStub(new Stub());
applet.init();
applet.start();
JFrame loader = new JFrame("Loader");
loader.setPreferredSize(applet.getSize());
loader.add(applet);
loader.pack();
loader.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
I would like it to render over the applet, but the applet still maintain all of its original functionality, I believe i would need to use reflection possibly? I was thinking about looking at the way Powerbot.org renders over the runescape client, as the client still maintains all its functionality etc.
If you have any questions or need to see more code, just ask.
Assuming this draws something (my applet-fu is rusty), then you can draw on top of it by placing it in a JFrame and subclassing the JFrames' void paint(Graphics g) so that it paints whatever it wants to, and then paints something else.
A modified JFrame that does this could be the following (warning: untested code):
public static class OverlayJFrame extends JFrame {
private JPanel overlay;
public OverlayJFrame(String title) { super(title); }
public void setOverlay(JPanel overlay) { this.overlay = overlay; }
public void paint(Graphics g) { super.paint(g); overlay.setSize(getSize()); overlay.paint(g)); }
}
Related
I'm trying to call repaint from another class. But it does not work. I have to draw on a frame.
public class Tester extends JFrame{
public static dtest d ;
public static void main(String[] args) {
Tester t = new Tester();
d = new dtest();
test tnew = new test();
}
public static class dtest extends JFrame implements MouseMotionListener{
public static int x,y;
dtest()
{
super("title");
setSize(500,500);
setVisible(true);
addMouseMotionListener(this);
}
#Override
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
public void paint(Graphics g)
{
System.out.println("I am called");
}
}
public static class test {
public test()
{
for(int i = 0 ; i < 5 ; i++)
{
System.out.println("I am called from run");
d.repaint();
}
}
}
}
this prints
I am called from run
I am called from run
I am called from run
I am called from run
I am called from run
so it does not executing the paint() portion. d.repaint() is not working. why?
Take a look at this page and look at the first answer. It's a similar if not exact question to yours.
JFrame's paint() method has been deprecated. The compiler, or your IDE, should be complaining a bit, especially if you place the #Override tag directly above the method (use this to test if this method can be rewritten... aka what you're trying to do).
This means that its use has been discouraged and some functionality may have been removed. When using javax.swing, you'll want to learn the system completely about JPanels and JComponents. To paint something on a screen, you'll want to add a custom class that extends JPanel with the add(Component c) method. Then, override the paintComponent(Graphics g) method in that class. Make sure to have the first line in that method be super.paintComponent(g); so that the window can refresh itself.
For completeness:
public class MyWindow extends JFrame {
MyPanel thePanel;
public MyWindow(int x, int y) {
setSize(x, y);
thePanel = new MyPanel(x, y);
this.add(thePanel);
}
}
public class MyPanel extends JPanel {
public MyPanel(int x, int y)
setSize(x, y);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(ImageManager.getImage("Cute Puppy"), 40, 40, null); // Or whatever
}
}
So, when the repaint() or revalidate() method is called on the MyWindow, the Panel will recieve a paintComponent call.
Please let me know in the comments if you need any additional help.
Edited:
Since you need to use MouseMotionListener, and I'm still not quite understanding the context and trouble of "I need to call repaint from another class"... I will try my best.
Firstly, check out this tutorial on the Oracle pages. Also, check out the others on GUI's. You'll learn a lot about organization and displaying that will make you realize how their system can work with yours.
Now, for your questions:
i have to use MouseMotionListener.
Not quite... it is a good way for set up but you can run a Thread (something that constantly runs methods over and over) to check the Mouse coordinates. You'll want to start doing this when you get into games and other miscellaneous applications.
new Thread() {
public void run() {
Point mouse;
int mousex;
int mousey;
while (true) {
mouse = MouseInfo.getPointerInfo().getLocation();
mousex = mouse.x - theWindow.getLocationOnScreen().x - 3; // You'll need to get the
// x coordinate, subtract the window's x coordinate, and subtract 3 because of
// the blue border around a standard pc window.
mousey = mouse.y - theWindow.getLocationOnScreen().y - 29; // 29 is top bar height
SomeOtherClass.processMove(mousex, mousey);
}
}
}.start();
Next: I tried that with JPanel but i could not do that. If you read the tutorial at the top of my edit, you see they implement MouseMotionListener with ease.
Next: I prefer to do it with JFrame. If you wish to process the mouse in the JFrame, do the following: Have your JFrame the listener, but the JPanel be where the mouse data comes from. As follows:
public class MyWindow extends JFrame implements MouseMotionListener {
public MyPanel thePanel;
public int x;
public int y;
public MyWindow() {
thePanel = new MyPanel();
thePanel.addMouseMotionListener(this);
// Make this JFrame get called when the mouse
// moves across the panel.
}
#Override
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
thePanel.repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
}
public class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Other painting stuff
}
}
Next: Now i have to update the frame from another class. I could not find a way to update the GUI(the frame) from another class.
Simple. Since the JPanel is what needs to be updated, add the following method to the MyWindow class:
public void repaintWindow() {
thePanel.repaint();
}
And add this to whenever you need to update it:
MyWindow theWindow = new MyWindow();
theWindow.repaintWindow();
Next: all the answers here extended JPanel. So i could not find my answer.
I apologize, but you NEED a panel. It is possible to do with JFrames, but if you want to start doing things raw and low-level, you need to learn how these things work by learning to read the oracle tutorials and the oracle documentation. For now, use JPanels in any ways I've shown you.
Next: from another class I have to draw something on JFrame.Is that possible?
Yes, indeed! Whenever you want to draw something:
MyWindow theWindow = new MyWindow();
Graphics g = theWindow.thePanel.getGraphics();
BufferedImage someRandomImage = SomeRandomClass.getRandomImage();
g.drawImage(someRandomImage, 200, 481, null);
theWindow.repaintWindow();
I really hope I've helped but to program in java you need to use the tools they give you, especially when it comes to high level things like Swing. There are tutorials everywhere for this stuff. Please read them before asking for specific help in the future.
ok i have two classes similar like this(the graphics are set up the same way) and another class that is displayed on the bottom. as you can see i have two graphics2ds that i would like to display at the same time with the items class being transparent and on top (the items class has almost nothing in it, and the game class is fully covered with pictures and such)
is there any way to do this?
currently the items class take priority ever the game class because it was called last and totally blocks the game class.
public class game extends Canvas implements Runnable
{
public game()
{
//stuff here
setBackground(Color.white);
setVisible(true);
new Thread(this).start();
addKeyListener(this);
}
public void update(Graphics window)
{
paint(window);
}
public void paint(Graphics window)
{
Graphics2D twoDGraph = (Graphics2D)window;
if(back==null)
back = (BufferedImage)(createImage(getWidth(),getHeight()));
Graphics graphToBack = back.createGraphics();
//draw stuff here
twoDGraph.drawImage(back, null, 0, 0);
}
public void run()
{
try
{
while(true)
{
Thread.currentThread();
Thread.sleep(8);
repaint();
}
}catch(Exception e)
{
}
}
}
class two
public class secondary extends JFrame
{
private static final int WIDTH = 800;
private static final int HEIGHT = 600;
public secondary()
{
super("Test RPG");
setSize(WIDTH,HEIGHT);
game game = new game();
items items = new items();
((Component)game).setFocusable(true);
((Component)items).setFocusable(true);
getContentPane().add(game);
getContentPane().add(items);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main( String args[] )
{
secondary run = new secondary();
}
}
Here are my suggestions:
Extend JComponent rather than Canvas (you probably want a lightweight Swing component rather than a heavyweight AWT one)
Then don't bother with the manual back-buffering for your drawing - Swing does back-buffering for you automatically (and will probably use hardware acceleration while doing so)
Have one component draw both items and the rest of the game background. There is no good reason to do it separately (even if you only change the items layer, the background will need to be redrawn because of the transparency effects)
Capitalise Your ClassNames, it makes my head hurt to see lowercase class names :-)
EDIT
Typically the approach would be to have a class that represents the visible area of the game e.g. GameScreen, with a paintCompoent method as follows:
public class GameScreen extends JComponent {
....
public void paintComponent(Graphics g) {
drawBackground(g);
drawItems(g);
drawOtherStuff(g); // e.g. animated explosions etc. on top of everything else
}
}
Say that I use a UrlClassLoader to load an applet from a website and attach it as a component to a frame. How can I gain control over the canvas so that I can draw to it myself? There is not much information about this as far as I can tell. Someone mentioned something about XBOOTING, but I have no idea what that is and I can't find anything about it.
The problem is that 'every applet is different'. That applet for instance, has no Canvas in it, but instead draws directly to the applet surface. As soon as you have an instance of the applet, you might draw directly to that, but it will be overwritten the moment that the user selects a button.
import java.applet.Applet;
import java.awt.*;
import java.net.*;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class GrabThatCanvas {
GrabThatCanvas() {
try {
String string = "http://mainline.brynmawr.edu/Courses/cs110/spring2002/Applets/Smiley/";
URL[] urls = {
new URL(string)
};
URLClassLoader urlcl = new URLClassLoader(urls);
Class<?> clss = urlcl.loadClass("Smiley");
Object o = clss.newInstance();
Applet applet = (Applet)o;
applet.init();
applet.start();
applet.setPreferredSize(new Dimension(200,200));
Canvas canvas = findFirstCanvas(applet);
if (canvas!=null) {
System.out.println("We have the Canvas!");
} else {
System.out.println("No Canvas found!");
}
JOptionPane.showMessageDialog(null, applet);
} catch (Exception e) {
e.printStackTrace();
}
}
/* Very naive implementation that assumes the canvas is added
* directly to the applet. */
public Canvas findFirstCanvas(Container parent) {
Canvas canvas = null;
Component[] components = parent.getComponents();
for (Component c : components) {
System.out.println(c);
if (c instanceof Canvas) {
canvas = (Canvas)c;
break;
}
}
return canvas;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new GrabThatCanvas();
}
});
}
}
Output
java.awt.Button[button0,0,0,0x0,invalid,label=Smile]
java.awt.Button[button1,0,0,0x0,invalid,label=Sad]
No Canvas found!
Of course, you might put the applet in a Swing GUI, account for the weird mix of Swing and AWT, and use the layered pane to draw 'over the top' of the entire applet. But that introduces new problems.
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())
I have a custom, abstract class 'Panel' which extends JPanel. There aren't many differences with the two when painting. I have a Panel and I'm simulating an animation by updating the x value of an image. I have two animations right now, one that properly repaints and another than does not. This is for the one that does not. The one that works will be labelled A, the one that doesn't will be B.
A and B follow the same format. Update some variable on the Panel, calls update (a method in Panel which calls PaintComponent) and then calls repaint. It calls repaint after because this issue was with A before and was solved that way.
A: Updates an image variable.
B: Updates the x variable of an image.
The Problem: The repaint doesn't clear the old image location and so it's a choppy mess across the screen.
What I've tried:
I've seen the super.PaintComponent(g) mentioned a lot, but this
hasn't solved the problem.
I've tried changing the order for when the repaint/update methods are
called.
Repaint does not update the Panel at all. (Probably because the
painting is done in PaintComponent)
Any help would be appreciated.
Code:
Panel:
public Panel (boolean visible){
super();
this.setLayout(new BorderLayout(640, 416));//sets the Layout type of the panel
this.setOpaque(false);//Makes it so that the panel underneath can be seen where images aren't drawn
this.setVisible(visible);
ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
gs = ge.getDefaultScreenDevice();
gc = gs.getDefaultConfiguration();
}
public void paintComponent (Graphics g){
setUp();
drawOff();
setDown(g);
}
private void setUp(){
off_screen = gc.createCompatibleImage(getSize().width, getSize().height, Transparency.TRANSLUCENT);
buffer = off_screen.createGraphics();
}
protected abstract void drawOff();
private void setDown(Graphics g){
g.drawImage(off_screen,0,0,this);
off_screen.flush();
}
public void update(){
paintComponent(this.getGraphics());
}
Animation Methods (mg is the panel in question):
private void battleStart(User user) {
for (int i = 0; i < user.battle.length; i++) {
mg.battleStart(user.battleStart(i));
mg.update();
try {
Thread.sleep(150);
} catch (Exception e) {
}
mg.repaint();
}
}
private void animateStart(User user){
for (int i = 0; i < 10; i++){
mg.x = mg.x + 10;
mg.update();
try {
Thread.sleep(100);
} catch (Exception e) {
}
mg.repaint();
}
}
I think your design is way off and that is why things are not working. I'm not quite sure how your non-abstract JPanels work, but consider making your parent JPanel something more along these lines:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class MyPanel extends JPanel {
private GraphicsEnvironment ge;
private GraphicsDevice gs;
private GraphicsConfiguration gc;
private BufferedImage offScreen;
public MyPanel(boolean visible) {
super();
this.setLayout(new BorderLayout(640, 416)); // strange constants for this layout.
this.setOpaque(false);
this.setVisible(visible);
ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
gs = ge.getDefaultScreenDevice();
gc = gs.getDefaultConfiguration();
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
setUp();
}
});
}
#Override
// don't make this public. Keep it protected like the super's
// just draw in this method. Don't call other methods that create buffers
// or draw to buffers.
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (offScreen != null) {
g.drawImage(offScreen, 0, 0, null);
}
}
private void setUp() {
offScreen = gc.createCompatibleImage(getSize().width, getSize().height,
Transparency.TRANSLUCENT);
}
// draw to the buffer outside of the paintComponent
// and then call repaint() when done
public void upDateOffScreen() {
// ?? offScreen.flush(); // I've never used this before,
// so am not sure if you need this here
Graphics2D osGraphics = offScreen.createGraphics();
// TODO: do drawing with osGraphics object here
osGraphics.dispose();
repaint();
}
}
Also and again,
Do all long processing methods off of the EDT (Event Dispatch Thread).
Never call Thread.sleep(...) on the EDT.
Consider using Swing Timers instead of using Thread.sleep for the animations.
It's OK to call repaint on your JPanel off of the EDT, but for the most part that's about it.
All other Swing methods should be called on the EDT.
Read, re-read, and study the 2D and Swing graphics tutorials.