Java - JComponent in polygon shape with background image - java

I want to have a JComponent on my JFrame, that has a custom shape in form of a polygon. Now i want to add a background image with colors in the same shape and blank color in the rest.
Is there a way to achieve this?
I have this test class:
public class Test extends JButton {
private final Polygon shape;
private final int provinceId;
private ImageIcon img;
public Test(Polygon p, int x, int y, int w, int h, int id, ImageIcon img) {
this.shape = p;
this.provinceId = id;
this.img = img;
setSize(w, h);
setLocation(x, y);
setIcon(img);
setContentAreaFilled(false);
addMouseListener(animation());
}
private MouseListener animation() {
return new MouseListener() {
public void mouseEntered(MouseEvent e) {
System.out.println("in");
}
public void mouseExited(MouseEvent e) {
System.out.println("out");
}
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
};
}
protected void paintComponent(Graphics g) {
g.drawPolygon(this.shape);
}
protected void paintBorder(Graphics g) {
g.drawPolygon(this.shape);
}
public boolean contains(int x, int y) {
return this.shape.contains(x, y);
}
public boolean isOpaque() {
return false;
}
public int getId() {
return this.provinceId;
}
public static void main(String[] args) {
JFrame f = new JFrame();
//Polygon p = new Polygon(new int[] {0, 400, 400, 0}, new int[] {0, 0, 300, 300}, 4);
Polygon p = new Polygon(new int[] {50, 150, 250, 350, 200, 50}, new int[] {0, 0, 50, 200, 300, 200}, 6);
ImageIcon ico = new ImageIcon("gfx/test.png");
Test t = new Test(p, 20, 20, 400, 300, 101, ico);
f.getContentPane().add(t);
f.setSize(500, 400);
f.setLayout(null);
f.setVisible(true);
}
}
but i only get this output: output
My original picture was: wanted output

You can do so by overriding the contains(Point p) method to only return true when p is in the bounds of your custom shape.
Then you best override isOpaque() to return false.
And finally you override paintComponent(Graphics g) to paint your component in whatever way you like (e.g. a background image with colors in the shape and blank color in the rest).
Sample code:
JPanel panel = new JPanel()
{
#Override
public boolean isOpaque()
{
return false;
}
#Override
public boolean contains(Point p)
{
// Use something that fits your shape here.
return p.getX() % 2 == 0;
}
#Override
public void paintComponent(Graphics g)
{
// do some painting
}
};

Related

Problems with JScrollBar in java

I am having a problem about JScrollBar.
In my application I have 2 panels (one fixed, and one that changes depending on what the user chooses in the menu)
In a given panel I have a JScrollPane with a table. Since the standard java scrollbar was outside the theme of the application, I decided to try to create another one.
I basically create a JScrollPane and change its scrollBar to a custom one I created (scrollPane.setVerticalScrollBar (new CustomScrollBar ()) ;.
The first time I present the panel, the scrollbar is perfect. However, when I change to another panel and go back to it, the scrollbar model has reset.
What could this be/how do I solve it?
Creation JScrollPane code:
JScrollPane tablePanel = new JScrollPane(table);
tablePanel.setBounds(10, 148, 495, 200);
tablePanel.setBorder(new EmptyBorder(0, 0, 0, 0));
tablePanel.setBackground(Color.WHITE);
tablePanel.setVerticalScrollBar(new CustomScrollBar());
add(tablePanel);
CustomScrollBar Code:
public class CustomScrollBar extends JScrollBar {
public CustomScrollBar() {
setOpaque(false);
setUI(new BasicScrollBarUI() {
private final Dimension d = new Dimension();
#Override
protected JButton createDecreaseButton(int orientation) {
return new JButton() {
#Override
public Dimension getPreferredSize() {
return d;
}
};
}
#Override
protected JButton createIncreaseButton(int orientation) {
return new JButton() {
#Override
public Dimension getPreferredSize() {
return d;
}
};
}
#Override
protected void paintTrack(Graphics g, JComponent c, Rectangle r) {
}
#Override
protected void paintThumb(Graphics g, JComponent c, Rectangle r) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Color color = null;
JScrollBar sb = (JScrollBar) c;
if (!sb.isEnabled() || r.width > r.height) {
return;
} else if (isDragging) {
color = Colors.superdarkPurple;
} else if (isThumbRollover()) {
color = Colors.lightPurple;
} else {
color = Colors.darkPurple;
}
g2.setPaint(color);
g2.fillRoundRect(r.x, r.y, r.width, r.height, 10, 10);
g2.setPaint(Color.WHITE);
g2.drawRoundRect(r.x, r.y, r.width, r.height, 10, 10);
g2.dispose();
}
#Override
protected void setThumbBounds(int x, int y, int width, int height) {
super.setThumbBounds(x, y, width, height);
scrollbar.repaint();
}
});
}
public JScrollBar geCustomScrollBar() {
return this;
}
EDIT 1
This goes to a panel to add questions
public void gotoAddQuestionsPanel(Question q) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
currentQuestionsPanel = "add";
updateFrameComponentTreeUI();
remove(subPanel);
if (q != null) {
addQuestionsPanel.setQuestion(q);
}
subPanel = addQuestionsPanel.getPanel();
subPanel.setBackground(Color.WHITE);
subPanel.setBounds(304, 0, 515, 415);
getContentPane().add(subPanel);
subPanel.setLayout(null);
}
});
}
And this goes back to what has the customized ScrollBar
public void gotoQueryQuestionsPanel() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
currentQuestionsPanel = "query";
updateFrameComponentTreeUI();
remove(subPanel);
subPanel = queryQuestionsPanel.getPanel();
subPanel.setBackground(Color.WHITE);
subPanel.setBounds(304, 0, 515, 415);
getContentPane().add(subPanel);
subPanel.setLayout(null);
}
});
}
public void updateFrameComponentTreeUI() {
SwingUtilities.updateComponentTreeUI(this);
}

Draw a rectangle over image in Java

I am trying to draw a rectangle over Image using java.awt classes. For that I used below sample code:
public class DrawRectangle {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setVisible(true);
}
});
}
}
class TestPane extends JPanel {
private BufferedImage myImage;
private Rectangle myOffice = new Rectangle(150, 50, 30, 20);
public TestPane() {
try {
File image = new File("C:\\Users\\NNaphade\\work\\ImageDetection\\Trial_Pascal_VOC\\test_image\\IMG_20180327_110210.jpg");
if(image.exists())
myImage = ImageIO.read(image);
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
System.out.println("image exist!!!!!!");
return myImage == null ? new Dimension(200, 200) : new Dimension(
myImage.getWidth(), myImage.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (myImage != null) {
g2d.drawImage(myImage, 0, 0, 1000, 1000, this);
g2d.setColor(Color.RED);
g2d.translate(0, 0);
g2d.draw(myOffice);
}
g2d.dispose();
}
}
This works correct and output is displayed as expected. Here I am fixing the parameters for rectangle as:
private Rectangle myOffice = new Rectangle(150, 50, 30, 20);
However, in my application, I want to pass these parameters from another method. I want to pass these x1, y1, w and h to TestPane class given above. I tried changing the TestPane constructor by passing these 4 parameters, but I am not able to set them as instance variables. E.g. the following code doesn't work.
private void markWithBoundingBox(INDArray testData, int gridWidth, int gridHeight, double w, double h, DetectedObject obj) {
double[] xy1 = obj.getTopLeftXY();
int predictedClass = obj.getPredictedClass();
int x1 = (int) Math.round(w * xy1[0] / gridWidth);
int y1 = (int) Math.round(h * xy1[1] / gridHeight);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane(x1, y1, w, h));
frame.pack();
frame.setVisible(true);
}
});
}
class TestPane extends JPanel {
private BufferedImage myImage;
//private Rectangle myOffice = new Rectangle(50, 50, 3, 20);
public TestPane(int x, int y, double w, double h) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
try {
File file = new File("C:\\Users\\NNaphade\\work\\ImageDetection\\Trial_Pascal_VOC\\test_image\\IMG_20180327_110210.jpg");
if(file.exists()) {
myImage = ImageIO.read(file);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Override
public Dimension getPreferredSize() {
return myImage == null ? new Dimension(100, 100) : new Dimension(
myImage.getWidth(), myImage.getHeight());
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (myImage != null) {
g2d.drawImage(myImage, 0, 0, 2000, 2000, this);
g2d.setColor(Color.RED);
g2d.translate(0, 0);
g2d.draw(new Rectangle(this.x, this.y, this.w, this.h));
}
g2d.dispose();
}
}
It seems to me that TestPane here is not a class but the component. because Java compiler doesn't let me declare the instance variables in the constructor and all the available methods there are of component. How can I get rid of this issue?

Unable to get rid of drawn lines

I found similar problems on the internet but the solutions provided didn't work.
I want to clear the JPanel. To do that I call repaint()(from the clear() method) with a flag set to false to avoid calling my drawing method (drawLines()). Drawn lines are still on the Panel.
I tried to repaint same lines again with the background color. This also didn't work.
public class WektPanel extends JPanel{
boolean check = false;
Color c = Color.BLUE;
boolean oval = false;
public WektPanel() {
setBackground(c);
setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(check)
drawLines(3, g);
}
void clear(){
check=false;
repaint();
}
void draw(){
check=true;
repaint();
}
void drawLines(int stroke, Graphics g){
g.drawLine(0,0,getWidth(),getHeight());
g.drawLine(0,getHeight(),getWidth(),0);
for(int i=1; i<stroke;i++){
g.drawLine(0+i,0,getWidth(),getHeight()-i);
g.drawLine(0,0+i,getWidth()-i,getHeight());
g.drawLine(0,getHeight()-i,getWidth()-i,0);
g.drawLine(0+i,getHeight(),getWidth(),0+i);
}
}
}
You're overriding paint(), but calling super.paintComponent(g). You should override paintComponent(g).
Edit: I couldn't follow your check logic. This worked for me.
public class Test {
private class WektPanel extends JPanel {
boolean clear;
public WektPanel() {
setBackground(Color.BLUE);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawLines(3, g);
}
public void clear() {
clear = true;
repaint();
}
public void draw() {
clear = false;
repaint();
}
private void drawLines(int stroke, Graphics g) {
if (!clear) {
g.drawLine(0, 0, getWidth(), getHeight());
g.drawLine(0, getHeight(), getWidth(), 0);
for (int i = 1; i < stroke; i++) {
g.drawLine(0 + i, 0, getWidth(), getHeight() - i);
g.drawLine(0, 0 + i, getWidth() - i, getHeight());
g.drawLine(0, getHeight() - i, getWidth() - i, 0);
g.drawLine(0 + i, getHeight(), getWidth(), 0 + i);
}
}
}
}
private void showGUI() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final WektPanel wektPanel = new WektPanel();
f.add(wektPanel, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
buttonPanel.add(new JButton(new AbstractAction("Clear") {
#Override
public void actionPerformed(ActionEvent e) {
wektPanel.clear();
}
}));
buttonPanel.add(new JButton(new AbstractAction("Draw") {
#Override
public void actionPerformed(ActionEvent e) {
wektPanel.draw();
}
}));
f.add(buttonPanel, BorderLayout.SOUTH);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().showGUI();
}
});
}
}
The first line in the paint method should be something like:
g.clearRect(0, 0, getWidth(), getHeight());
This way you make sure that the previous paints will not be there when you start painting again.

Java - draw graphics using a method and a constructor

I am working on a java 2d game library. I want a method named paintImage() to do graphics.drawImage() every time paintImage() is called.
public void paintImage(image1, x, y){
//i want it to run graphics.drawImage every time it is called.
}
public void anotherMethod(){
paintImage(...);
paintImage(...);
//paint as many times as i want.
}
public void paintComponent(Graphics graphics){
graphics.drawImage();
super.paintComponents();
}
Thanks for your time and please leave a suggestion, sorry but its kind of hard to explain this.
For Single Image Display
public class DrawingDemo {
private JPanel panel;
private MyImage imageData;
public DrawingDemo() {
...
panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (imageData != null) {
g.drawImage(imageData.getImage(), imageData.getX(), imageData.getY(), this);
}
}
};
...
}
public void paintImage(Image image1, int x, int y) {
imageData = new MyImage(image1, x, y);
panel.repaint();
}
public void anotherMethod() {
paintImage(...);
paintImage(...);
}
}
public class MyImage { // bean class for storing image information
private Image image;
private int x;
private int y;
public MyImage(Image image, int x, int y) {
this.image = image;
this.x = x;
this.y = y;
}
public Image getImage(){
return image;
}
public int getX(){
return x;
}
public int getY(){
return y;
}
... you can add setter methods
}
UPDATE : For multiple image display
private JPanel panel;
private ArrayList<MyImage> imageData; // or any other data structure you like
public DrawingDemo() {
imageData = new ArrayList<>();
JFrame frame = new JFrame();
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (MyImage myImage : imageData) {
g.drawImage(myImage.getImage(), myImage.getX(), myImage.getY(), this);
}
}
};
frame.add(panel);
frame.setVisible(true);
}
public void paintImage(Image image1, int x, int y) {
imageData.add(new MyImage(image1, x, y));
panel.repaint();
}
public void anotherMethod() {
paintImage(new ImageIcon("/home/blackadmin/Desktop/image.jpg").getImage(), 0, 0);
paintImage(new ImageIcon("/home/blackadmin/Desktop/image2.jpg").getImage(), 50, 50);
paintImage(new ImageIcon("/home/blackadmin/Desktop/image3.jpg").getImage(), 100, 100);
}
OUTPUT :
Have a look at this answer
Comment if you don't understand anything, hope this will help
What I think you're looking to do is to make changes to some states in your class and then redrawing your images with changes based on those state changes -- in other words perhaps you're looking to do animation. If so, then your image drawing should all be done either within the paintComponent method using its Graphics object, or in another method called by paintComponent one that uses the Graphics object passed into paintCocalzmponent. This can be done by passing a Graphics parameter into the other method. Your anotherMethod would then request that the JVM repaint the GUI by calling repaint(). For example:
public void anotherMethod() {
x++;
y++;
repaint(); // this will stimulate JVM to call paint/paintComponent
}
private void paintImage(Graphics g, BufferedImage img, int x, int y2) {
g.drawImage(img, x, y2, this);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
paintImage(g, image1, x, y);
}
A complete example of this is as follows:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.beans.Transient;
import javax.swing.*;
public class PaintEg extends JPanel {
private static final int IMG_W = 30;
private static final int IMG_H = IMG_W;
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int TIMER_DELAY = 20;
private BufferedImage image1;
private int x;
private int y;
public PaintEg() {
image1 = createImg();
new Timer(TIMER_DELAY, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
anotherMethod();
}
}).start();
}
private BufferedImage createImg() {
BufferedImage img = new BufferedImage(IMG_W, IMG_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setBackground(Color.red);
g2.clearRect(0, 0, IMG_W, IMG_H);
g2.setColor(Color.blue);
g2.fillRect(IMG_W / 4, IMG_H / 4, IMG_W / 2, IMG_H / 2);
g2.dispose();
return img;
}
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void anotherMethod() {
x++;
y++;
repaint(); // this will stimulate JVM to call paint/paintComponent
}
private void paintImage(Graphics g, BufferedImage img, int x, int y2) {
g.drawImage(img, x, y2, this);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
paintImage(g, image1, x, y);
}
private static void createAndShowGUI() {
PaintEg paintEg = new PaintEg();
JFrame frame = new JFrame("PaintEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(paintEg);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

Custom JScrollbar Problem (change the knob/thumb)

I want to change the look of a JScrollBar.
I do this with overwriting/extending ScrollBarUI.
It´s no problem to change the outlook of the arrowbuttons by overwriting createIncreaseButton and createDecreaseButton.
I change the width of the track by overwriting paintThumb and paintTrack Methods.
It looks now like <----o----> (a very thin trackline and an oval thumb/knob).
PROBLEM:
The knob can't move till the very end:
What it does look like: <---o------>
What it should look like: <---------o>
I know this is because I made the oval not stretching (the original rectangle stretches with the width).
I'm totally clueless as were to change the computing of the thumb move so it can move until the end.
I would be very thankful for help.
Heres the code:
public class TestScrollBarMain extends JFrame {
public TestScrollBarMain() {
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
JPanel p = new JPanel();
p.setPreferredSize(new Dimension(500, 500));
JScrollPane s = new JScrollPane(p);
MyScrollBar b = new MyScrollBar();
s.setVerticalScrollBar(b);
getContentPane().add(s);
setSize(100, 100);
setVisible(true);
}
public static void main(String[] args) {
new TestScrollBarMain();
}
public class MyScrollBarUI extends BasicScrollBarUI {
#Override
protected void paintThumb(final Graphics g, final JComponent c, final Rectangle thumbBounds) {
if (thumbBounds.isEmpty() || !this.scrollbar.isEnabled()) {
return;
}
g.translate(thumbBounds.x, thumbBounds.y);
g.setColor(this.thumbDarkShadowColor);
g.drawOval(2, 0, 14, 14);
g.setColor(this.thumbColor);
g.fillOval(2, 0, 14, 14);
g.setColor(this.thumbHighlightColor);
g.setColor(this.thumbLightShadowColor);
g.translate(-thumbBounds.x, -thumbBounds.y);
}
#Override
protected void paintTrack(final Graphics g, final JComponent c, final Rectangle trackBounds) {
g.setColor(Color.black);
g.fillRect(trackBounds.width / 2, trackBounds.y, 3, trackBounds.height);
if (this.trackHighlight == BasicScrollBarUI.DECREASE_HIGHLIGHT) {
this.paintDecreaseHighlight(g);
} else if (this.trackHighlight == BasicScrollBarUI.INCREASE_HIGHLIGHT) {
this.paintIncreaseHighlight(g);
}
}
}
public class MyScrollBar extends JScrollBar {
MyScrollBar() {
super();
setUI(new MyScrollBarUI());
}
}
}
Include this on your MyScrollBarUI code:
protected void setThumbBounds(int x, int y,int width,int height)
{
super.setThumbBounds(x, y, 14, 14);
}
protected Rectangle getThumbBounds()
{
return new Rectangle(super.getThumbBounds().x,super.getThumbBounds().y,14,14);
}
protected Dimension getMinimumThumbSize()
{
return new Dimension(14,14);
}
protected Dimension getMaximumThumbSize()
{
return new Dimension(14,14);
}

Categories