I have a BufferedImage displayed in a JFrame through my own class. I opted to display the BufferedImage using my own class so I can scale it. My paintComponent and update
public class MyBuffIm{
public void paintComponent(Graphics canvas) {
if (bi == null) {
} else {
//bi, maxWidth, and maxHeight were passed to constructor
canvas.drawImage(bi, 0, 0, maxWidth, maxHeight, null);
}
}
public void update(Graphics canvas) {
super.update(canvas);
if(bi != null){
//Got this from some tutorial in the net.
//Done out of desperation :|
paintComponent(bi.getGraphics());
}
}
}
I overrode update since the docs are saying something like "If this component is not a lightweight component, the AWT calls the update method in response to a call to repaint". I'm not exactly sure if my component is lightweight or not.
In any case, I have the following code in my Runnable (does not work as I expect it to):
BufferedImage p = SomeMyBuffIm.getBuffIm();
Vector<Point> randomPixels = getRandomPixels(500);
int limit = randomPixels.size()
for (i = 0; i < limit; i++) {
Point rp = randomPixels.get(i)
p.setRGB(rp.x, rp.y, Color.red.getRGB());
}
SomeMyBuffIm.repaint();
mainFrame.repaint(); //JFrame call to repaint
I'd like to think that, since I'm scaling my image, I just can't discern the difference between the new and old images. But I've tried the largest values for getRandomPixels still to no effect. My test image, by the way, is just a white sheet so red pixels should stand out in it.
Anything wrong I'm doing?
I overrode update since the docs are saying something like "If this component is not a lightweight component, the AWT calls the update method in response to a call to repaint". I'm not exactly sure if my component is lightweight or not.
No you should NOT override update(). You would do that with AWT but not with Swing.
If you update the BufferedImage then all you need to do is invoke repaint() on your instance of the MyBuffin class.
If you need more help than post your SSCCE that demonstrates the problem.
Related
I have two functions within a class
void display()
and
void write(PGraphics pdf)
I use display() to display elements to the screen. Is there a way of invoking the code within display() so that I do not have to write out each of the functions again within write(pdf)? e.g.
line(0,0,100,100) to pdf.line(0,0,100,100) etc
You could do this by drawing to a PGraphics image instead of drawing directly to the screen, then draw that image to the screen. That way you could swap it out for the PDF PGraphics without changing any code. Something like this:
PGraphics pg;
PGraphics pdf;
boolean usePdf = false;
void setup() {
size(100, 100);
pg = createGraphics(width, height);
pdf = //whatever
}
void draw(){
if(usePdf){
display(pdf);
}
else{
display(pg);
image(pg, 0, 0);
}
}
void display(PGraphics g) {
g.beginDraw();
g.background(100);
g.stroke(255);
g.line(20, 20, mouseX, mouseY);
g.endDraw();
}
If you want to use all of the code jsut call it inside (but I guess you don't want to do that)
You should refractor the code and put the stuff you want to use in both methods into it's own method like:
private void hopefullyIGetABetterName(...) {...}
You can call this method inside of display as well as in write
I hope this helps, otherwise feel free to ask :-)
extract a common interface between drawing to screen and to the PDF (lets call it Drawable)
Implement Drawable for drawing to the screen.
Implement Drawable for drawing to the PDF
Create a single draw method that takes that interface.
Change display() to call draw(screenDrawable)
Change write(...) to call draw(pdfDrawable)
Since I'm new I can't post more than two links, but this is an x-post from reddit.com/r/learnprogramming, just for full disclosure.
I'll basically just be pasting what I said there to here. Thanks for your help, if you can help.
I'm writing somewhat of a graphing application. I currently only have it able to graph sin(x), but that's not the point of this question. I am not able to draw to my main panel. Here is what it currently looks like.
I had an overridden paint function in my Window.java class, which drew the sin(x) function and the axes, but when I made an inner class which extended JPanel(), it would no longer draw.
I then tried to make a separate file, but that didn't draw anything either.
What could be preventing it from drawing?
Here are all my files in question.
edit: code in question:
GraphDraw.java:
//import stuff
Public class GraphDraw extends JPanel {
SinX sinx = new SinX();
GraphPanel p = new GraphPanel();
#Override
public void paintComponent(Graphics gc) {
super.paintComponent(gc);
Graphics2D g = gc;
p.paintComponent(g);
sinx.paint(g);
}
}
And in Window.java, I initialize GraphDraw and add it to my main panel, which is underneath the buttons in the picture and above the x/y min/max labels.
GraphDraw drawer = new GraphDraw();
/*
GUI code
*/
mainPanel.add(drawer);
SinX.java
//import stuff
public class SinX extends Component {
public void paint(Graphics g) {
g.setColor(Color.red);
for(double x=-400;x<=400;x=x+0.5) {
double y = 50 * sin(x*((Math.PI)/180));
int Y = (int)y;
int X = (int)x;
g.drawLine(400+X,300-Y,400+X,300-Y);
}
}
}
First, before anything else, do the following:
Change you object from Component to JComponent
Do not ever, ever call paintComponent() or paint() on a graphics object from swing or awt, use object.repaint(); (For reasons I won't go into here, because it's long and complicated)
From there I would try calling setVisible(true); on all your objects. If you are getting this code from a tutorial, then stop and use a different tutorial. You need to learn how swing and the AWT library work before you can start making user interfaces. Nobody uses AWT anymore because Swing is much better. For reasons why, look at the following page. If you are too lazy to do that, its because it's more optimized and more powerful.
What is the difference between Swing and AWT?
Ok, so, what I've been trying to figure out is how I can make a custom MouseListener for all my buttons that would not require listing every single one of them in the Handler, because I'm going to have a lot of them. Here's the code I have in my Listener as of now:
package com.dinobuilding.handler;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import com.BLANK.BLANKScreen;
import com.BLANK.BLANKWindow;
import com.BLANK.menufeature.Button;
public class ButtonHandler implements MouseListener {
public BLANKWindow dbw;
public BLANK Screen dbs;
static Button button = new Button();
public int buttonX = button.x;
public int buttonY = button.y;
public int buttonSizeX = button.xSize;
public int buttonSizeY = button.ySize;
public ButtonHandler(BLANKWindow dbw, BLANKScreen dbs) {
this.dbw = dbw;
this.dbs = dbs;
}
public static void setButton(Button b) {
button = b;
}
public int mouseEventX;
public int mouseEventY;
Graphics g;
public void mouseClicked(MouseEvent e) {
mouseEventX = e.getLocationOnScreen().x;
mouseEventY = e.getLocationOnScreen().y;
if(mouseEventX <= buttonX && mouseEventX >= buttonX + buttonSizeX) {
if(mouseEventY <= buttonY && mouseEventY >= buttonY + buttonSizeY) {
button.onClicked(dbs, dbw, g);
}
}
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
And here's the code in the first button that I'm trying to implement:
package com.BLANK.menus;
import java.awt.Color;
import java.awt.Graphics;
import com.BLANK.BLANKScreen;
import com.BLANK.BLANKWindow;
import com.BLANK.handler.ButtonHandler;
import com.BLANK.menufeature.Button;
public class MainMenuPlayButton extends Button {
public static int x;
public static int y;
public static int xSize;
public static int ySize;
public static String s;
public static Graphics g;
public MainMenuPlayButton(int x, int y, int xSize, int ySize, String s, Graphics g) {
super(x, y, xSize, ySize, s, g);
this.x = x;
this.y = y;
this.xSize = xSize;
this.ySize = ySize;
this.s = s;
this.g = g;
setColor(new Color(0, 226, 26));
draw();
}
public MainMenuPlayButton() {
}
public static void draw() {
drawButton(x, y, xSize, ySize, g, s);
ButtonHandler.setButton(new MainMenuPlayButton());
}
public void onClicked(BLANKScreen dbs, BLANKWindow dbw, Graphics g) {
setColor(new Color(216, 0, 0));
}
I think my main problem is that the code in the ButtonHandler gets called before the code in the Button class and therefore the ButtonHandler is utilizing the Button class itself, not the MainMenuPlayButton class. If you need the Button class as well, simply tell me, however I can't imagine why. Thank you in advance!
Edit
Ok, after debugging some, I have found that I in fact have the opposite problem. The button is never being clicked. The getSource() method could work, however I don't really know how to use that and I don't think that I could use that without hardcoding every single button, which is really something I do not want to do.
EDIT 1:
Do you think maybe I could do use the MouseEvent's getX or getXOnScreen? By the way, I registered the ButtonHandler using frame.addMouseListener on my JFrame, so...
EDIT 2:
It would seem that the getX method does not work either. If you could help me on that, I would very much appreciate that.
If you want to get the object that was pressed and tripped the MouseListener, use the MouseEvent's getSource() method. For example, this might work:
public void mouseClicked(MouseEvent e) {
(YourButton) button = (YourButton) e.getSource();
button.onClicked(...);
}
Other bits:
Rename your class from Button to something else, since the Button name clashes with the java.awt.Button class, and this can cause difficult to debug errors.
I cringe any time I see a Graphics field declared in a class, as it suggests possible inappropriate painting. Make sure that you really know what you're doing if you ever use one of these as a field since it's easy to get image loss or a NullPointerException if not used correctly, since the Graphics object is frequently changed by Java, and this change is completely out of your (the programmer's) control. Don't say that you haven't been warned.
Edit
Regarding your comments:
Yes, I do know what I'm doing with the Graphics field, however, if it makes you feel better, know that it's only temporary and I will be changing it to something else later.
OK, I've just been burned on this before. As long as you get it from a BufferedImage and don't try to get it by calling getGraphics() on a component or by pulling it out of a paint or paintComponent method, then you might be OK.
Also, I'm pretty sure that I'm getting the object it clicked correctly, but I can't get it to access the correct subclass of Button. It's only getting the Button class itself, not the MainMenuPlayButton.
Sorry, but this doesn't make sense since you don't get "classes" when you obtain a reference, an object pure and simple, and in fact you would get the very same object that the ButtonListener was added to and that tripped the listener, and the class of this reference will be whatever class your button is. I am assuming that you're adding your MouseListener directly to your "Button" object, correct? Again, time to do some debugging.
Edit 2
Regarding the most recent edit to your question:
Ok, after debugging some, I have found that I in fact have the opposite problem. The button is never being clicked. The getSource() method could work, however I don't really know how to use that and I don't think that I could use that without hardcoding every single button, which is really something I do not want to do.
No, there is no need to hard-code each button, trust me. That's the whole reason for using listeners that are added to the buttons.
EDIT 1: Do you think maybe I could do use the MouseEvent's getX or getXOnScreen? By the way, I registered the ButtonHandler using frame.addMouseListener on my JFrame, so... the
There's one of your problems. If you want to listen to your buttons, you're going to want to be able to register listeners on the button itself. If you have an array or collection of them registering listeners is easy. And no, I don't recommend using x and y on screen since it makes your program extremely fragile. If you did this, any changes to the structure of your GUI would require subsequent hard-code changes to your x and y handling. Ugh.
This begs the question of why create your own Button class, and why not instead use JButtons or a subclass of JButtons. You appear to be re-inventing the wheel, but (sorry to be blunt) creating one that is square.
Edit 3
But you cast the variable to a button, meaning that if I have multiple buttons I have to cast each and every one of them to a different thing.
No absolutely not as the magic of polymorphism should work here. But they're objects of the same type, no? Or do you have many different subclasses of your Button class? And regardless, inside of the mouseClicked(...) method, you appear to want to call only one method on your button, onClicked(...), which I imagine has to be an object of the super class, right? So by calling this method on the current button, It should call its own correct code.
The problem I have with JButton is that they already exist. I can't edit them and I can't customize them, ...
This is patently not true. You can change their appearance and behaviors by many means, including by subclassing or by a factory creation method. Plus they already come with the machinery for being able to register listeners and respond to mouse actions.
...Also, would I have to register/make a new handler for each and every one of the buttons?
Again, you appear to be forgetting that polymorphism should take care of all of this. One handler should do, depending on how well-behaved your code is.
I am going to have a LOT of buttons, and I don't think that that would be a viable solution. If not the getX how would I get it to do something when the thing is clicked?
I've given you my recommendation, other than sometimes it is better to re-write sections of code if the design can be improved, meaning again you may want to consider retrofitting your code to use JButtons.
I am working on a custom JSlider that has a custom Track Rectangle. I want the ability to set the color of the track rectangle when first declaring the slider.
Here's a snippet of what I have (The classes are in separate files in the same package):
public class NewSlider extends JSlider {
Color kolor;
public NewSlider (Color k) {
kolor = k;
}
public void updateUI() {
setUI(new NewSliderUI(this, kolor);
updateLabelUIs();
}
}
public class NewSliderUI extends BasicSliderUI {
Color sliderColor = Color.BLACK;
public NewSliderUI (JSlider b, Color k) {
super(b);
sliderColor = k;
}
}
In the above code, "kolor" is initially null and leads to and error when NewSliderUI tries to use it. It appears that the updateUI() method is called before anything else. Then the NewSlider constructor is called. I have tried a variety of things, but because updateUI() appears to run before anything else, nothing I add to the NewSlider class seems to matter.
If I hardcode a Color (ie. setUI(new NewSliderUI(this, Color.BLACK);), then it works, but having a different class for each color seems silly.
Thanks.
I don't see how kolor could be null unless one of the following are happening:
You're passing a null value to the constructor
You're not instantiating NewSlider in the Swing EDT and are having some strange cache issues
NewSlider is being constructed via reflection/deserialization and kolor is not being set.
Have you tried running this in the debugger with some breakpoints? I'd be curious to ensure that the NewSlider constructor is being called (and before the NewSliderUI constructor).
Edit: I see what you mean below. I forgot that the no args constructor for JSlider was being called implicitly. What about doing the following:
public class NewSlider extends JSlider {
Color kolor = Color.BLACK;
public NewSlider (Color k) {
kolor = k;
updateUI();
}
public void updateUI() {
setUI(new NewSliderUI(this, kolor);
updateLabelUIs();
}
}
You end up calling updateUI() twice, but the end result should be what you want.
I have been attempting to enhance my GUI system written in Java to use subpixel antialiasing and have been successful, except for two remaining anomalies. This is a follow on to my other question from a few weeks ago.
The first problem is that setting rendering hints KEY_ANTIALIASING to VALUE_ANTIALIAS_ON causes KEY_TEXT_ANTIALIASING to be ignored when it is set to an LCD (subpixel) AA value. Can anyone shed some light on this? Currently I am forced to VALUE_ANTIALIAS_OFF before rendering text and turn it back on after rendering text (so that other painting, like circles, etc, is AA'd). This problem is proven by the self-contained test program below.
The second problem is that I can find no way to query the underlying O/S setting for AA, so I have to do a rather kludgey workaround, which is to create a Swing JLabel, get it's FontMetrics, get it's FontRenderContext and then get the AA hint from that. Apart from involving Swing in a program that otherwise makes absolutely no use of Swing, it will not work on a device running any J2ME JVM. Can anyone suggest a better way to do this? It's OK if it requires J5 or J6, since the current kludge already requires J6 (but needing only J4 would be best). I have already tried every default setting and using an AWT component instead of JLabel.
Test Program
This program verifies that for subpixel AA to work, the general AA setting must first be disabled. (PS: I write to a back-buffer because my underlying GUI does, and I wanted to test in an equivalent context).
import java.awt.*;
import java.awt.event.*;
public class AwtTestFrame1b extends Panel {
private final Font font=new Font(Font.SANS_SERIF, Font.PLAIN, 16);
private final int line=25;
AwtTestFrame1b() {
setBackground(SystemColor.control);
}
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
int py=0;
py=paintText(g2d,py,null ,false);
py=paintText(g2d,py,null ,true );
py+=line;
py=paintText(g2d,py,RenderingHints.VALUE_TEXT_ANTIALIAS_OFF ,false);
py=paintText(g2d,py,RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT ,false);
py=paintText(g2d,py,RenderingHints.VALUE_TEXT_ANTIALIAS_ON ,false);
py=paintText(g2d,py,RenderingHints.VALUE_TEXT_ANTIALIAS_GASP ,false);
py=paintText(g2d,py,RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB,false);
py+=line;
py=paintText(g2d,py,RenderingHints.VALUE_TEXT_ANTIALIAS_OFF ,true );
py=paintText(g2d,py,RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT ,true );
py=paintText(g2d,py,RenderingHints.VALUE_TEXT_ANTIALIAS_ON ,true );
py=paintText(g2d,py,RenderingHints.VALUE_TEXT_ANTIALIAS_GASP ,true );
py=paintText(g2d,py,RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB,true );
py+=line;
}
private int paintText(Graphics2D g2d, int py, Object val, boolean aa) {
Graphics2D dgc=g2d;
char[] txt=("The quick brown fox jumped over the lazy dog ("+val+", General AA: "+aa+")").toCharArray();
Image img=null;
GraphicsConfiguration cfg=getGraphicsConfiguration();
img=cfg.createCompatibleImage(getWidth(),line);
dgc=(Graphics2D)img.getGraphics();
dgc.setColor(getBackground());
dgc.fillRect(0,0,getWidth(),line);
dgc.setColor(g2d.getColor());
if(aa ) { dgc.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON ); }
else { dgc.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF); }
if(val!=null) { dgc.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,val); }
dgc.setFont(font);
dgc.drawChars(txt,0,txt.length,10,line-5);
g2d.drawImage(img, 0,py, null);
dgc.dispose();
img.flush();
return (py+line);
}
public static void main(String[] args) {
Frame wnd=new Frame("AWT Antialiased Text Sample");
wnd.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
wnd.add(new AwtTestFrame1b());
wnd.setSize(new Dimension(1000, 600));
wnd.setVisible(true);
}
}
Are the AWT Desktop Properties of any help? In particular, "awt.font.desktophints" - these contain the AA hints that the native components use, but can be applied to any Graphics2D you want.
Just a shot in the dark, having recently read through the AA section in Filthy Rich Clients.
Use would look something like this:
String str = "A quick brown fox jumps over the lazy dog";
Toolkit tk = Toolkit.getDefaultToolkit();
Map desktopHints = (Map)(tk.getDesktopProperty("awt.font.desktophints"));
Graphics2D g2d = (Graphics2D)g;
if(desktopHints != null) {
g2d.addRenderingHints(desktopHints);
}
g2d.drawString(str, someX, someY);
I was able to get the same results (using your example class and drawChars and drawImage, just typed drawString for simplicity) as the LCD HRGB mode using these hints and no other calls on my machine.
I'm not sure what release of Java this requires, if it's what you're looking for...
Don't forget: "Implementations are free to ignore the hints completely." For reference, here's what I see at 24 points: