Blurred image instead of solid colours? - java

I am using BufferedImage for my background but when I reproduce it with the following code to make it bigger why does my image code produce blurred edges instead of solid colours?
public final class State_Play extends State_Template {
private BufferedImage background;
private int[] pixelelements;
private int width,height;
State_Play(){
init();
}
public void init(){
width=8; //Configuration.appwidth,
height=6; //Configuration.appheight
background=new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
pixelelements=((DataBufferInt) background.getRaster().getDataBuffer()).getData();
maketuringarray();
}
public void maketuringarray(){
int singlecolor=new Random().nextInt();
pixelelements[new Random().nextInt(width*height)]=singlecolor | 0xFF000000;
}
#Override
public void update() {
maketuringarray();
}
#Override
public void render(Graphics g) {
g.drawImage(background, 0, 0, Configuration.appwidth, Configuration.appheight, null);
}
Instead of solid colours?

Most likely the problem is that the interpolation on your platform is by default set to cubic or bicubic. This will make upscaling blurry.
Explicitly set it to nearest neighbour, to get the "blocky pixel" effect you want (if I understand you correctly):
#Override
public void render(Graphics g) {
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
g.drawImage(background, 0, 0, Configuration.appwidth, Configuration.appheight, null);
}

Related

Can't write animation for JComponent to smoothly change rectangle'a colors to grey

I faced the problem that I can't write an animation for color change at the Rectangle of JComponent. I use Java 8 and Swing. This animation is supposed to be slow, for any amount of seconds I would like to set. Nit: It feels like the base which I need to wrote his thing is definetly timer.
Here is the code snippet which describes my component's state:
class PBtn extends JComponent {
private LinkedList<MyBtn> myBtns = new LinkedList<>();
LinkedList<MyBtn> getMyBtns(){
return myBtns;
}
static class MyBtn extends Rectangle {
String name;
Color color;
MyBtn(int x, int y, int width, int height, String name, Color color) {
this.setBounds(x, y, width, height);
this.color = color;
}
}
void addBtn(int x, int y, int width, int height, String name, Color color) {
MyBtn myBtn = new MyBtn(x, y, width, height, name, color);
this.addMouseMotionListener(new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent e) {}
#Override
public void mouseMoved(MouseEvent e) {
if (myBtn.contains(e.getPoint())) {
setToolTipText(name);
}
ToolTipManager.sharedInstance().mouseMoved(e);
}
});
myBtns.add(myBtn);
repaint();
}
void clearBtns() {
myBtns.clear();
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D graphics2D = (Graphics2D) g;
myBtns.forEach(n -> {
graphics2D.setColor(n.color);
graphics2D.draw(n);
graphics2D.fill(n);
});
}
I tried to use the interpolation-based animation library bu it didn't help. Can you please give me suggestions how to write this code from scratch? Thanks!

JSlider image behind track

I want to put an image (visualization of an audio) behind the JSlider which represents the audioplayer, the process of playing.
First I tried to overwrite the paint-method of the Slider
public void paintComponent(Graphics g) {
// Draw the previously loaded image to Component
g.drawImage(img, 0, -100, null);
super.paintComponent(g);
}
this worked, but the image is higher than the slider, so my next try was a JLayeredPane, where I put the JSlider above a JLabel with the image. Looks good for the first moment. But I mentioned that I need the image behind the track of the slider, not the whole slider. There is space to the left and right. Can anybody tell me a way how to calculate this space? Or the width and offset of the track to the border of the slider? This should run under Windows and MacOs, so different LookAndFeels, so I think hard coded values will not work.
Example Slider with background image
Thankyou.
My solution for this Problem is now to overwrite the SliderUI. So this is a very special component, so it's nonrelevant that it looks the same on all LookAndFeels.
It supports also jumping directly to mouse position, which is different to BasicSliderUI.
/**
*
* Custom SliderUI for AudioPlayer with audioimage in background
*/
public class AudioSliderUI extends BasicSliderUI {
private BasicStroke stroke = new BasicStroke(1f, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND, 0f);
public AudioSliderUI(AudioSlider b) {
super(b);
}
#Override
public void paint(Graphics g, JComponent c) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
super.paint(g, c);
}
#Override
protected Dimension getThumbSize() {
return new Dimension(2, 200);
}
#Override
public void paintTrack(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Stroke old = g2d.getStroke();
g2d.setStroke(stroke);
g2d.setPaint(Color.WHITE);
if (slider.getOrientation() == SwingConstants.HORIZONTAL) {
g2d.drawLine(trackRect.x, trackRect.y + trackRect.height / 2,
trackRect.x + trackRect.width, trackRect.y + trackRect.height / 2);
} else {
g2d.drawLine(trackRect.x + trackRect.width / 2, trackRect.y,
trackRect.x + trackRect.width / 2, trackRect.y + trackRect.height);
}
g2d.setStroke(old);
Image img = ((AudioSlider)slider).getImage();
g2d.drawImage(img, trackRect.x, trackRect.y, trackRect.width, trackRect.height, slider);
}
#Override
public void paintThumb(Graphics g) {
Rectangle knobBounds = thumbRect;
int w = knobBounds.width;
int h = 100;
int newStarty = knobBounds.height/2- h/2;
g.translate(knobBounds.x, knobBounds.y);
// "plain" version
g.setColor(Color.YELLOW);
g.fillRect(0, newStarty, w, h);
}
#Override
protected TrackListener createTrackListener(JSlider slider) {
return new TrackListener() {
#Override
public void mousePressed(MouseEvent e) {
if (UIManager.getBoolean("Slider.onlyLeftMouseButtonDrag")
&& SwingUtilities.isLeftMouseButton(e)) {
JSlider slider = (JSlider) e.getComponent();
switch (slider.getOrientation()) {
case SwingConstants.VERTICAL:
slider.setValue(valueForYPosition(e.getY()));
break;
case SwingConstants.HORIZONTAL:
slider.setValue(valueForXPosition(e.getX()));
break;
default:
throw new IllegalArgumentException(
"orientation must be one of: VERTICAL, HORIZONTAL");
}
super.mousePressed(e); // isDragging = true;
super.mouseDragged(e);
} else {
super.mousePressed(e);
}
}
#Override
public boolean shouldScroll(int direction) {
return false;
}
};
}
}
Matching Slider:
public class AudioSlider extends JSlider {
private Image img;
public AudioSlider() {
setOpaque(false);
}
/**
* #return the img
*/
public Image getImage() {
return img;
}
public void setImage(Image img) {
this.img = img;
}
}
Works for me, maybe covers not all prospects.

Painting multiple JComponent on JPanel not working

I just don't get this. I want to add Highlight extends JComponent objects to a PdfPage extends JPanel but the Highlight components are simple not painted. I can see that their paint() and paintComponent() methods are getting called in correct order but they do not show. The only thing that fixes my problem is to add:
for(Component component : this.getComponents()) {
component.paint(g);
}
into the PdfPanel.paint() method but this is not how I want to do that. I want PdfPage extends JPanel to render any JComponent I'm adding but not override paint() if possible.
This is how I add Highlight components to PdfPage panels:
for (DatasheetError datasheetError : datasheetErrorList) {
int pageNumber = datasheetError.getPageNumber();
Highlight highlight = createErrorHighlight(datasheetError);
PdfPage pdfPage = pdfPages[pageNumber];
pdfPage.add(highlight);
}
This is how PdfPage looks like. Note that I am not using a LayoutManager as I am calling super(null);:
public class PdfPage extends JPanel {
private static final long serialVersionUID = 7756137054877582063L;
final Image pageImage;
public PdfPage(Image pageImage) {
// No need for a 'LayoutManager'
super(null);
this.pageImage = pageImage;
Rectangle bounds = new Rectangle(0, 0, pageImage.getWidth(null), pageImage.getHeight(null));
this.setBounds(bounds);
this.setLayout(null);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
paintPdfPage(g);
}
private void paintPdfPage(Graphics g) {
// For now transparent background to see if `Highlight` gets painted
g.setColor(new Color(1.0f, 1.0f, 1.0f, 0.0f));
g.fillRect(0, 0, getWidth(), getHeight());
}
}
In Highlight.java you can see that I call this.setBounds(bounds);
public class Highlight extends JComponent {
private static final long serialVersionUID = -1010170342883487727L;
private Color borderColor = new Color(0, 0, 0, 0);
private Color fillColor;
public Highlight(Rectangle bounds, Color fillColor) {
this.fillColor = fillColor;
this.setBounds(bounds);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle bounds = this.getBounds();
g.setColor(this.fillColor);
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
g.setColor(this.borderColor);
g.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
}
}
Looks like problem is coordinate space
protected void paintComponent(Graphics g) {
...
Rectangle bounds = this.getBounds();
g.setColor(this.fillColor);
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
...
}
The getBounds() returns the component's rectanle on parent container. So when you can call just g.fillRect(0, 0, bounds.width, bounds.height);

Drawing with a JPanel's getGraphics()?

I've run into a bit of a wall here. I read elsewhere while trying to fix this issue that you are never supposed to getGraphics(). The problem is, I can't use the provided Graphics context from the paint() / paintComponent() methods. I require it to only call my generate(Graphics g) function once, and I can not provide Graphics outside of the override functions.
Any tips? Trimmed for your convenience.
public class Main extends JPanel {
...
static JFrame displayFrame, inputFrame;
...
...
// Generator node list
ArrayList<Node> nodes = new ArrayList<Node>();
public static void main(String[] args) {
// Set up the frame
screenSize = Toolkit.getDefaultToolkit().getScreenSize();
displayFrame = new JFrame("City generator");
displayFrame.setSize(screenSize.width / 3, screenSize.width / 3);
displayFrame.setLocation(screenSize.width / 2 - displayFrame.getWidth()
/ 2, screenSize.height / 2 - displayFrame.getHeight() / 2);
displayFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
displayFrame.add(new Main());
// displayFrame.setUndecorated(true);
displayFrame.setBackground(Color.lightGray);
displayFrame.setVisible(true);
displayFrame.addMouseMotionListener(new MouseAdapter() {
public void mouseMoved(MouseEvent e) {
// Mouse movement events here
}
});
}
// Override function
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Calls multiple times
generate(g);
}
private void generate(Graphics g) {
............................
Instead of painting directly to the Graphics context, you could generate a BufferedImage image of what you want painted and paint to that instead...
private BufferedImage buffer;
public BufferedImage generate() {
if (buffer == null) {
buffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_IMAGE_ARGB);
Graphics2D g2d = buffer.createGraphics();
// Paint away...
g2d.dispose();
}
return buffer;
}
Then you would paint the result within the paintComponent method...
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Calls multiple times
BufferedImage img = generate();
g.drawImage(img, 0, 0, this);
}
As an example...
Why not just keep a boolean value to track if generate() has been called.
public boolean calledGenerate = false;
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (!calledGenerate) generate(g);
}
void generate(Graphics g) {
calledGenerate = true;
....
}
also you are calling AWT/Swing code outside of the EDT which is a bad idea.
In your main function you normally should call:
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
//build your awt/swing objects here
}
});
What does generate() do though? There is probably a better way to do it.

How do I make my custom bitmap button field use a transparent background?

I have a custom bitmap buttonfield that completely works, however, the background behind the image is showing a white rectangle. I've found where it makes the color white, but I cannot figure out how to make it completely transparent. Any ideas? I'm programming in blackberry java JDE 5.0
FYI The button image is a rounded corner png file that uses transparency on the corners
Code:
public class BitmapButtonField extends Field
{
Bitmap _currentPicture;
private Bitmap _onPicture;
Bitmap _offPicture;
private int id;
public BitmapButtonField (Bitmap onImage, Bitmap offImage)
{
super(Field.FOCUSABLE|Field.FIELD_HCENTER);
_offPicture = offImage;
_onPicture = onImage;
_currentPicture = _onPicture;
}
public void setButtonImage (Bitmap onImage, Bitmap offImage)
{
_offPicture = offImage;
_onPicture = onImage;
_currentPicture = _onPicture;
}
public void setButtonId(int id)
{
this.id = id;
}
public int getButtonId()
{
return this.id;
}
public int getPreferredHeight()
{
return _onPicture.getHeight();
}
public int getPreferredWidth()
{
return _onPicture.getWidth();
}
protected void onFocus(int direction)
{
_currentPicture = _offPicture;
invalidate();
}
protected void onUnfocus()
{
_currentPicture = _onPicture;
invalidate();
}
protected void drawFocus(Graphics g, boolean on)
{
g.setBackgroundColor(Color.BLACK);
}
protected void layout(int width, int height)
{
setExtent(Math.min( width, getPreferredWidth()), Math.min(
height, getPreferredHeight()));
}
protected void paintBackground(Graphics g) {
int prevColor = g.getColor();
int prevAlpha = g.getGlobalAlpha();
g.setColor(Color.YELLOW);
g.setGlobalAlpha(0);
g.fillRect(0, 0, getWidth(), getHeight()); // or g.getClippingRect()
g.setColor(prevColor);
g.setGlobalAlpha(prevAlpha);
}
protected void paint (Graphics graph){
graph.setColor(Color.WHITE);
//super.paint(graph);
graph.fillRect(0, 0, getWidth(), getHeight());
graph.drawBitmap(0, 0, getWidth(), getHeight(),
_currentPicture, 0, 0);
}
protected boolean navigationClick(int status, int time)
{
fieldChangeNotify(0);
return true;
}
public boolean keyChar(char key, int status, int time)
{
if (key == Characters.ENTER)
{
fieldChangeNotify(0);
return true;
}
return false;
}
}
Make sure your paint() method uses drawARGB to draw the bitmap on screen. I had a similar problem, "Scale a Bitmap and preserve alpha, on BlackBerry", and it turned out that drawRGB and drawBitmap don't make use of the alpha channel, so won't leave anything transparent.
your are using
graph.setColor(Color.WHITE);
graph.fillRect(0, 0, getWidth(), getHeight());
method in your code (in paint() and paintBackground() method) which will create a white rectangle.
I think you need to remove this code.
if you still not able to find issue then i will provide another Custom BitmapField example.
You have implemented
protected void drawFocus(Graphics g, boolean on)
and
protected void paintBackground(Graphics g)
And you have also specified the background image for focused state. You can remove the implementation of paintBackground() and drawFocus(). Also the line which set the graphics color to white and fills a rectangle can be deleted from the method paint. That is you need to only paint the bitmap image on the paint method. I have modified your code here, You can check that (I didn't test it).

Categories