Unable to drawimage on null layout swing - java

I want to draw some images on screen alongside some JButtons placed in different places of the screen. However whenever I have setLayout(null); the images do not show up on screen. If i don't set it to null I can make the images show up but I can't place my Jbuttons on the desired places.
How can i make so i have setLayout(null); and still be able to draw multiple images on screen while placing my buttons anywhere?
My Frame Class:
public class PFrame extends JFrame {
JPanel p;
public PFrame() {
p = new PPanel();
p.setBackground(Color.WHITE);
Container c = getContentPane();
c.setLayout(null);
c.add(p);
setSize(1200,700);
JRadioButton White = new JRadioButton("White");
ButtonGroup G1 = new ButtonGroup();
White.setBounds(1000, 30, 80, 50);
G1.add(White);
this.add(White);
//rest of buttons code here...
public class PPanel extends JPanel{
public void paintComponent(Graphics g) {
super.paintComponent(g);
Image [] vi = ImgArray();
int x = 0;
int y = 0;
int i;
for (i = 0; i < vi.length / 2; i++) {
g.drawImage(vi[i],x,y,240,310,null);
x+= 250;
}
y = 320;
x = 0;
for (i = vi.length / 2; i < vi.length; i++) {
g.drawImage(vi[i],x,y,240,310,null);
x+= 250;
}
}
}
Main method:
public static void main(String[] args) {
PersonagensFrame f =new PFrame();
f.setVisible(true);
f.repaint();
}

I would recomend using anything other then a null layout for swing. You should check out the documentation for layouts such as GridBagLayout and GridLayout; since they are much more friendly in terms of compatibility.
If that isn't what you are looking for, you should also try making two seperate panels, seperating your buttons and images.
Swing was specifically built to incorporate layouts in which they provide.
I hope you figure it out! :)

Related

Adding multiple circles to a JFrame? (Java)

I am trying to draw circles to JFrame with different positions, in this case in a grid-like pattern.
I don't seem to have trouble drawing a single circle with an x,y position, however, when I try to draw multiple circles with different positions the other circles' positions come out obscured.
In the code below, I have two arrays: XPlacements and YPlacements that contain different X and Y positions to form a grid. For each X position there should be circles created at that X position with varying Y positions (vice versa).
When I only make the below code draw one circle, where XPlacements = {10} YPlacements = {100}, it draws a circle that appears to be at some (10,100) from the top left. Similarly when I add multiple X positions but a single Y position nothing seems to be obscured. However, when I add multiple Y positions, every descending row of circles seems to be more and more pushed to the right.
When I run it, it obscures like this: http://imgur.com/HHjhvPD
I can't seem to make it less obscured by changing the values of the JFrame. All the JFrame circle tutorials I can find only deal with 1 circle, and I don't have any issues when I use 1 circle (or only 1 row of circles).
Does anyone know why the code below isn't producing a grid like pattern?
Thanks.
public class Circle extends Canvas {
int XPos;
int YPos;
public void SetPosition(int x, int y) {
this.XPos = x;
this.YPos = y;
repaint();
}
public void paint(Graphics g) {
System.out.println("Filling oval with position ("+XPos+","+YPos+")");
g.fillOval(XPos, YPos, 15, 15);
}
}
public class MainFile extends JFrame {
static int[] XPlacements = {10,20,30};
static int[] YPlacements = {100,200,300};
static Circle[] Circles = new Circle[1000];
static int Circle_Count = 0;
public static void main(String[] args) {
JFrame frame = new JFrame("Grid of circles");
frame.setLayout(new GridLayout(1,1));
frame.setSize(800, 800);
for(int x=0;x<XPlacements.length;x++) {
for(int y=0;y<YPlacements.length;y++) {
System.out.println("Creating new circle "+Circle_Count+" with position "+XPlacements[x]+","+YPlacements[y]);
Circles[Circle_Count] = new Circle();
Circles[Circle_Count].SetPosition(XPlacements[x],YPlacements[y]);
frame.add(Circles[Circle_Count]);
Circle_Count++;
}
}
frame.setVisible(true);
}
}
First of all this is a Swing application so custom painting should be done by overriding paintComponent() of a JPanel. A Canvas is an AWT component that should not be used in a Swing application.
If you want to draw on a component then the custom painting is always done relative to offset (0, 0). So in your case the code would be:
//g.fillOval(XPos, YPos, 15, 15);
g.fillOval(0, 0, 15, 15);
Then you need to override the getPreferredSize() method of your class to set the size of the component:
#Override
public Dimension getPreferredSize()
{
return new Dimension(15, 15);
}
Read the section from the Swing tutorial on Custom Painting for more informations and working examples.
Now the layout manager has information about the component and can position each component on the panel:
So the code to add the Circles to the frame would be something like:
frame.setLayout( new GridLayout(3, 3, 50, 50) );
for (int i = 0; i < 9; i++)
{
frame.add( new Circle() );
}
This will create a 3x3 grid with a gap of 50 pixels between each component.

Simple way to provide a scrollable image view (waveform) in Java without using ImageIcon?

Is there a Java-only way to show larger pictures in a JScrollPane? I don't want to reinvent the wheel and I'm already struggling at showing 32768x400 images using the ImageIcon in a JLabel trick because there seem to be limits regarding the ImageIcon that are platform dependent. Ubuntu 16.10 won't show any ImageIcon of the size 32768x400, though it shows smaller ones. Win10 shows them all.... and there is not even any error output of any sorts, which is terrible because I just wasted time searching for the problem.
So is there any easy solution to this that does not require me to reinvent the wheel?
In particular, I want to display waveforms, ie. an array of floats, so there is actually no need to have an overall image at all.
I believe this shows how to do what you want. Note how the Graph component has a width of 65535. This could be further optimized by only drawing the visible part of the graph as you scroll, but it's fairly fast as it is.
import java.awt.*;
import javax.swing.*;
import java.util.function.Function;
class Graph extends JComponent {
private Function<Double, Double> fun;
public Graph(Function<Double, Double> fun) {
this.fun = fun;
setPreferredSize(new Dimension(65535, 300));
}
public void paintComponent(Graphics g) {
// clear background
g.setColor(Color.white);
Rectangle bounds = getBounds();
int w = bounds.width;
int h = bounds.height;
g.fillRect(bounds.x, bounds.y, w, h);
// draw the graph
int prevx = 0;
int prevy = fun.apply((double)prevx).intValue();
g.setColor(Color.black);
for (int i=1; i<w; i++) {
int y = fun.apply((double)i).intValue();
g.drawLine(prevx, prevy, i, y);
prevx = i;
prevy = y;
}
}
}
public class Wf {
public static void main(String[] args) {
JFrame f = new JFrame();
// we're going to draw A sine wave for the width of the
// whole Graph component
Graph graph = new Graph(x -> Math.sin(x/(2*Math.PI))*100+200);
JScrollPane jsp = new JScrollPane(graph);
f.setContentPane(jsp);
f.setSize(800, 600);
f.setVisible(true);
}
}

Adding a JScrollPane to an overriden JPanel

I am trying to create a program that computes for the Round Robin algorithm. The logic works fine. My problem is with the overriden JPanel that I use to draw the timeline. The timeline goes on and on without definite line length. I want to add the overriden panel to a scroll pane so it can be scrollable.
SampleGPane.class
import java.awt.*;
import javax.swing.*;
public class
SampleGPane
{
/* Timeline elements */
Container timelineContainer;
JFrame timelineFrame = new JFrame ();
JPanel pnlDraw = new JPanel ();
JScrollPane timelineScroll;
public void
launchFrame ()
{
GPanel gpane = new GPanel ();
timelineContainer = timelineFrame.getContentPane ();
timelineScroll = new JScrollPane (gpane);
timelineContainer.add (timelineScroll);
timelineFrame.setSize (500, 250);
timelineFrame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
timelineFrame.setVisible (true);
}
private class
GPanel extends JPanel
{
#Override
public void
paintComponent (Graphics g)
{
super.paintComponent (g);
int runningLineX = 0;
int runningLineY = 0;
// g.drawLine (50, 50, orderCount * 5, 50);
runningLineX += 50;
runningLineY += 50;
for (int count = 0; count < 35; count++) {
g.drawString ("J" + (count + 1), runningLineX + 50, 25);
runningLineX += 50;
// runningLineY += 50;
g.drawLine (runningLineX, runningLineY, runningLineX + 50, runningLineY);
}
}
}
}
SampleGPane.class is called by SampleLaunch.class
public class
SampleLaunch
{
public static void main (String args[]) {
SampleGPane sgp = new SampleGPane ();
sgp.launchFrame ();
}
}
The problem is, the JScrollPane won't work. It doesn't seem to detect the line. How do I fix this?
You need to override the getPreferredSize() method of your custom panel to return a reasonable size.
The scrollbars will only appear when the preferred size of the component added to the viewport of the scroll pane is greater than the size of the scroll pane.
The timeline goes on and on without definite line length.
The line length will need to match your painting code. So you need parameters to control what to paint. These parameters will also be used in the calculation of the size of the component. In your example you iterate 35 times and increment the x by 50 so the width would be 1750 plus the starting x offset.

Changing the position of images on the JFrame

So I am making this ABC learning game , What I want to do is if I click on the A button more than once then , the three Images will change their position, What I want to do is this
![enter image description here][1]
When I click on A button, the three image will appear on the screen, the first is apple as I set it that way in the loop, but the second two images will appear randomly, though sometimes one o them is apple again, I could fix that.
My Question is, how can I change that position of the Apple to the second and second image to the first and third image to the second position if the "A" button is clicked more than once.
SO, the result will be the apple will change position based on the click "A" button and other two picture changes their position and chosed randomly from the array.
So, here is my code for the JPanel, where everything takes place.Most of the code is explained in the comments
import java.awt.*;
import java.awt.event.ActionListener;
import javax.swing.*;
import java.awt.event.*;
import java.text.AttributedCharacterIterator;
import java.util.Random;
import javax.swing.ImageIcon;
/**
*
* #author Dip
*/
public class AbcGeniusPanel extends JPanel implements ActionListener {
//Declare the necessary Variables here
private JButton[] buttons; //create an array for buttons
private BorderLayout layout; //Declare object of BorderLayout
private Image image = null;
private boolean showImage = false;
//Initialize all the variables here
static int index = 0;
int randNumber = 0, id = 0;
int q = 0, w = 0;
int buttonClick = 0;
//Store all the imahges that will appear on the screen into an String type array
private static String[] imageList = {"src/Images/1.png", "src/Images/2.png", "src/Images/3.png", "src/Images/4.png", "src/Images/5.png", "src/Images/6.png", "src/Images/7.png", "src/Images/8.png", "src/Images/9.png", "src/Images /10.png",
"src/Images/11.png", "src/Images/12.png", "src/Images/13.png", "src/Images /14.png", "src/Images/15.png",
"src/Images/16.png", "src/Images/17.png", "src/Images/18.png", "src/Images /19.png", "src/Images/20.png",
"src/Images/21.png", "src/Images/22.png", "src/Images/23.png", "src/Images /24.png", "src/Images/25.png",
"src/Images/26.png"
};
//Define the constructor here
public AbcGeniusPanel() {
ImageIcon[] alphabets = new ImageIcon[26];
setBackground(Color.yellow);
//Load the images for alphabet images into the alphabets array using a for loop
for (int i = 0; i < alphabets.length; i++) {
alphabets[i] = new ImageIcon("C:\\Users\\Dip\\Desktop\\Java Projects\\AbcGeniusApp\\src\\Alphabets\\" + (i + 1) + ".png");
}
//Create a JPnael object
JPanel panel = new JPanel();
//Set a layoutManager on the panel
//panel.setLayout(new FlowLayout(FlowLayout.CENTER)); //This is not workling good
panel.setLayout(new GridLayout(2, 13, 5, 5)); //This is good for now
//Create an array for holdoing the buttons
buttons = new JButton[26];
//This Loop will Store the buttons in the buttons array attatching each image for each button
//Try passing Images inside the JButton parameter later.
for (int i = 0; i < 26; i++) {
buttons[i] = new JButton(alphabets[i]);
}
// Now Setting up a new Borderlayout so that we can set the whole gridLayout at the botton of the panel
setLayout(new BorderLayout(2, 0));
//add the panel to the Border layout
add(panel, BorderLayout.SOUTH);
//Add evenHandling mechanism to all the buttons
for (int k = 0; k < 26; k++) {
buttons[k].addActionListener(this);
}
for (int count1 = 0; count1 < 26; count1++) {
panel.add(buttons[count1]);
}
}
//This Method will generate a random Number and return it
public int random_number() {
int rand_num;
Random generator = new Random(System.currentTimeMillis());
rand_num = generator.nextInt(26);
return rand_num;
}
//This method will draw the font on the Panel
public void paintComponent(Graphics g) {
Font font; //Declare Font object here
font = new Font("Wide Latin", Font.BOLD, 22); //Set font
super.paintComponent(g); //Ensure the drawing in super class
g.setFont(font); //Set the font
g.setColor(Color.RED);
String text = "CLICK ON THE RIGHT IMAGE!"; //Display the text
g.drawString(text, 255, 20);
}
//To draw the picture on the screen we need to override the paint Method
#Override
public void paint(Graphics g) {
super.paint(g);
//Here, x and y will determine the x and y position os each image
int x = 0, y = 0;
// the varibale q is declared above
for (q = 0; q < 3; q++) //This loop will generate three images on the screen
{
if (showImage) {
x = x + 265; //X-Position of the image
y = 90; //Y-Position of the image
//q is declared as q=0, so this will always be true
if (w == 1 || q == 0) {
g.drawImage(image, x, y, image.getWidth(null), image.getHeight(null), null); //This method will put the image on the screen
showImage = true;
w = 0;
}
while (true) //this loop will run anyway
{
//go inside this loop only when the generated random
//doesn't match with the index of the button that was pressed
while ((randNumber = random_number()) != index) {
index = randNumber; //Now put the randomVlaue in the index
this.image = new ImageIcon(imageList[randNumber]).getImage();
showImage = true;
//make w=1 so that we can break from the outer loop
w = 1;
//break from the inner loop
break;
}
//Since we have made the w=1, so we are breaking out of the outer loop
if (w == 1) {
break;
}
}
}
}
}
#Override
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
id = 0;
while (true) {
//id is set to zero, for example if the button A (buttons[0])is not pressed then it will go below
//to increase id until it matches the index of the button that we pressed
if (source == buttons[id]) {
//get the image of that same index of the buttons and then set the showImage true
//SO the the paint function above can draw the image
this.image = new ImageIcon(imageList[id]).getImage();
showImage = true;
//save the index of the button that is presed in another variable
//then break from the while loop
index = id;
break;
} else {
id++;
//This is necessary to make sure that id will cross 26
//becasue we have only 26 letters or the array index is 26
//so highest value can be 26 only
id = id % 26;
}
}
repaint();
}
}
Add 3 JLabels or JButtons (whatever will be displaying the images) into a JPanel container. The JPanel will likely use a GridLayout(1, 3, horizontal_gap, 0) layout.
Place all images as ImageIcons into an ArrayList.
Shuffle the ArrayList when needed
After shuffling place the Icons into the JLabels/JButtons in a for loop using the setIcon(...) method.
Note that
your JPanel should override paintComponent, not paint. The paint method is responsible for painting a component's children and borders, and it does not use double buffering by default, making a more dangerous method to override.
Putting in a while (true) loop into your Swing GUI without regard to threading is extremely dangerous.
Putting this into a painting method such as paint is GUI suicide. Never do this since a painting method is a major determinant in the perceived responsiveness of your program. If you slow it down, the program will be perceived as being slow and poorly responsive, and thus it must be lean and fast as possible, and you should have painting and only painting code within it.
Your paint method has program logic in it, something that also shouldn't be done. You don't have full control over whether or even if a painting method will be called, and so program logic should never be placed inside one of these.
As MadProgrammer well notes, don't use the src path for your images as this won't exist once you build your program into a jar file. Better to Create a resource directory in the jar file, and to refer to your images as resources, not as files.

How to implement actionListener on BufferedImage multiple times

I am currently designing an image editor in a GUI which has several buttons which, when clicked, should apply different effects on the loaded image. I have the effects working with an ActionListener but if I try to click an effect after already clicking another effect, the image turns black instead of applying the desired effect. How do I apply multiple effects to the same image? Here is my code for the ButtonPanel class, which includes the ActionListener and code for the effects(only three of the effects have been implemented as of yet):
class ButtonPanel extends JPanel
{
//JButton makeBlue;
BufferedImage img;
ImagePanel ip = new ImagePanel();
ButtonPanel(ImagePanel x)
{
final JButton makeBlue = new JButton ("Make Blue");
final JButton makeRed = new JButton ("Make Red");
final JButton makeGreen = new JButton ("Make Green");
final JButton invertColors = new JButton ("Invert Colors");
final JButton makeGreyscale = new JButton ("Greyscale");
final JButton makeWarhol = new JButton ("Warhol");
final JButton flipVertical = new JButton ("Flip Vertical");
final JButton flipHorizontal = new JButton ("Flip Horizontal");
final JButton rotateClockwise = new JButton ("Rotate Clockwise");
setBackground(Color.RED);
ip = x;
//int width, height;
//setBackground(Color.RED);
//int height = 0;
add(makeBlue);
add(makeRed);
add(makeGreen);
add(invertColors);
add(makeGreyscale);
add(makeWarhol);
add(flipVertical);
add(flipHorizontal);
add(rotateClockwise);
ActionListener action =
new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
BufferedImage img = ip.getImg();
if (e.getSource()== makeBlue)
{
int width = img.getWidth(); //# of pixel columns
int height = img.getHeight(); //# of pixels rows
for(int i=0; i<width;i++)
{
for(int j=0; j<height; j++)
{
int value = img.getRGB(i,j);
int y = 0xFF0000FF;
value = value & y;
img.setRGB(i,j,value);
}
}
ip.setImage(img);
setBackground(Color.GREEN);
repaint();
}
else if(e.getSource()== makeRed)
{
int width = img.getWidth(); //# of pixel columns
int height = img.getHeight(); //# of pixels rows
for(int i=0; i<width;i++)
{
for(int j=0; j<height; j++)
{
//fill in code here
int value = img.getRGB(i,j);
int y = 0xFFFF0000;
value = value & y;
//System.out.println(value);
img.setRGB(i,j,value);
}
}
ip.setImage(img);
repaint();
}
else if(e.getSource()== makeGreen)
{
int width = img.getWidth(); //# of pixel columns
int height = img.getHeight(); //# of pixels rows
for(int i=0; i<width;i++)
{
for(int j=0; j<height; j++)
{
//fill in code here
int value = img.getRGB(i,j);
int y = 0xFF00FF00;
value = value & y;
img.setRGB(i,j,value);
}
}
ip.setImage(img);
repaint();
}
}
};
makeBlue.addActionListener(action);
makeRed.addActionListener(action);
makeGreen.addActionListener(action);
makeWarhol.addActionListener(action);
flipVertical.addActionListener(action);
flipHorizontal.addActionListener(action);
rotateClockwise.addActionListener(action);
makeGreyscale.addActionListener(action);
invertColors.addActionListener(action);
}
}
Any help would be appreciated. Thanks.
Your problem is that you're extracting all of one color out of the image, and then replacing the original image in your ImagePanel with the new extracted image that is, say if the green button is pressed, all green. Then when you try to extract red from the ImagePanel's image, you get all black because the image is now only green.
You need to save the original image somewhere if you want to extract the original colors. Perhaps you should give ImagePanel a method, getOriginalImage() or some such, and have it store two images, one the displayed image and one the changed one.
Better still, use an Model-View-Control pattern and store your images elsewhere off the GUI.
There are two ways to accomplish this. You can either have your class be the ActionListener (which is the way you have it set up now), or you can have a unique ActionListener for each button. As a design decision I prefer the latter, as you can have more precise control and easier to read code this way.
Each of your buttons, menu items, and any other Object you want to have a unique effect should each have it's own ActionListener. You can either write a new class file for each ActionListener, an inner class, or an anonymous inner class for each. I prefer anonymous inner classes placed in line of your constructor or setup method like this:
JButton testButton = new JButton("Test");
testButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
// do stuff here
System.out.println("You clicked me!");
}
});
This method allows you to ignore huge conditional branches and unnecessary comparisons. Implement the interface uniquely for each component that needs the listener.

Categories

Resources