I know I am being an idiot and that's why I can't figure it out but I am trying to paint a bunch of rectangles with randoms size and position using paintComponent. I am trying to make sure that all of them are painted within the frame. I am able to do it with the following code (snippet) but I am wondering if there is a better way to do it than me hardcoding numbers into the program. Is there a method that I should take a look at that might be what I'm looking for?
Here's the inner class that overrides the paintComponent() method:
class DrawPanel extends JPanel {
public void paintComponent(Graphics g) {
int red = (int)(Math.random()*256);
int blue = (int)(Math.random()*256);
int green = (int)(Math.random()*256);
g.setColor(new Color(red, blue, green));
//The following 4 lines keep the rects within the frame
//The frame is 500,500
int ht = (int)(Math.random()*400);
int wd = (int)(Math.random()*400);
int x = (int)(Math.random()*100);
int y = (int)(Math.random()*100);
g.fillRect(x,y,ht,wd);
}
}
You should base your co-ordinates & sizes on the DrawPanel component size. Also using Random.nextInt instead of Math.random() will make it easier to keep within range based on the current size of the panel:
Random random = new Random();
int ht = random.nextInt(getHeight());
int wd = random.nextInt(getWidth());
int x = random.nextInt(getWidth() - wd);
int y = random.nextInt(getHeight() - ht);
I am wondering if there is a better way to do it than me hardcoding numbers into the program.
Yes there is
call getSize() on the enclosing JPanel, the DrawPanel, so you can see the actual boundaries of the component that is being drawn upon. (edit: or getWidth() and getHeight() as recommended by Lucas -- 1+ to his answer!).
Also, you will usually want to call the super's paintComponent(...) method within the child's override.
Also you will usually want to do your randomization elsewhere, such as in the DrawPanel's constructor so as not to change your rectangles each time you re-size the GUI.
There is a method to get the length and width of the panel you are working in.
getHeight();
getWidth();
These will return the current size of the JPanel you are working in, meaning if you resize the window it'll actually still draw them inside.
http://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#getWidth()
Related
I have created a GUI via Netbeans Java but whenever I maximize the GUI window the text boxes become misaligned. I used the Netbeans drag and drop function to create the GUI. I was wondering why the text boxes become misaligned whenever I maximize the GUI
It's an issue with the layout.
Read up on using layouts: http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
If you are going to use Netbean's GUI builder, run through a tutorial. It'll help you better understand how the builder is to be used. https://netbeans.org/kb/docs/java/quickstart-gui.html
I Understood your problem because I already had the same problem, My advice to you is that you can use the drag and drop of netbeans but before using it first make a panel and in that panel drop all your stuff then using the JFrame Component re sized function just put the panel wherever you want to put it for e.g if you want to center align it.
//if your class is extending JFrame
public static int getWIDTH(){
return WIDTH;
}
public static int getHEIGHT() {
return HEIGHT;
}
private void formComponentResized(java.awt.event.ComponentEvent evt) {
// this is for setting panel in the middle of the JFrame horizontally
int a = getWIDTH();
int b = Panel.getWidth();
a = a/2;
b = b/2;
int centerForX = b - a;
// This is for setting the panel in the middle vertically
int x = getHEIGHT();
int y = Panel.getHeight();
x = x/2;
y = y/2;
int centerForY = x - y;
// Making a 'Point' object and then setting location of the Panel.
Point p = new Point(centerForX , centerForY);
Panel.setLocation(p);
}
Some Keypoints:
1) getWIDTH and getHEIGHT methods will be generated by netbeans write outside all methods but in the class the getwidth and getheight and press ctrl + space and press enter and the getWIDTH and getHEIGHT methods will be generated respectively.
2) the formComponentResized method will be generated by netbeans, just go to design tab and then in the Navigator which is mostly in the bottom left right click on JFrame and then goto events then components and then componentResized.
3) If you have any question don't hesitate to ask, as I have detailed knowledge of this topic.
Is there anything obvious wrong with this line of code? I want rectangle to stay centered regardless the size of the window. But this donĀ“t work for some reason, the rectangle stays the same place.
public void run() {
setSize(800, 800);
createEntireFigure();
}
private void createEntireFigure(){
int centerOfWindowWidth = getWidth() / 2;
int centerOfWindowHeight = getHeight() / 2;
GRectWithGLabel ("A String",centerOfWindowWidth, centerOfWindowHeight);
}
Your rectangle size code is only called on rectangle creation, and so it makes sense that the rectangle's position will not change if the GUI is re-sized. You need to somehow listen for size changes in your GUI and call code to re-position the rectangle then for this to work. What graphics library are you using?
SOLVED:
Just found out what the problem was, after trying to make an SSCCE.
It had to do with my cell class, I didn't realise I was overriding getX() and getY() from the JComponent class.
After renaming these accessors it all works as expected
========================================
I have a JPanel with a GridLayout set at 3 rows x 3 cols.
I'm trying to add JPanels to each cell in the gridlayout to fill up all 9 cells.
Each one of these JPanels has an overriden paintChildren method which will paint some kind of rectangle starting at the top left of the JPanel - the end result will be each cell has a rectangle in it starting at the top left of the cell.
After adding all the JPanels to the gridlayout, they all appear in the top left corner overlapping each other (I have confirmed they are overlapping), instead of being laid out in a 3x3 grid.
How can I get them arranged in the 3x3 grid?
(Simplified) Code:
public class Panel extends JPanel {
public Panel(int x, int y) {
layout = new GridLayout(x, y, 2, 2);
setLayout(layout);
populateGrid();
}
public void populateGrid() {
removeAll();
for (int i = 0; i < 9; i++)
add(new Cell(50,50));
}
}
public class Cell extends JPanel {
public Cell(int x, int y) {
// x/y values used to define rectangle
setBorder(BorderFactory.createLineBorder(new Color(0,0,0)));
setBackground(Color.WHITE);
}
public void paintChildren(Graphics g) {
g.setColor(Color.BLUE);
g.fillRect(0, 0, x, y);
}
}
Make sure you import the right Panel. (And not the java.awt.Panel class.) Or, better, rename your class to GridPanel or something similar to avoid confusion / clashes.
You probably don't want to override paintChildren. Overriding paintComponent sounds like a better option in this case.
You may want to set minimum / preferred / maximum size for the Cell class.
Hard to make more observations without the actual code that instantiates and uses your Panel class.
My code plots 5000 points of time series data in a panel that is 581 pixels wide by default, but this width changes when the user resizes the window. My code also plots several rectangular markers that each identify a local maximum/peak in this same space.
I need to enable the user to right click on any of the rectangular-peak-markers so that the user can manually delete any false peak. The problem is that my code is reporting different x-coordinates than expected when the user right-clicks on a peak-marker. I suspect that the reason may have to do with rounding error in converting from 581 x-pixels back to 5000 data indices. But I am not certain of the reason.
Can anyone suggest a solution that enables my users to manually select one of the above-described peak markers by right-clicking on it?
I am enclosing relevant sections of the code below. My actual code is very, very long, and too complicated to post. But the relevant portions below should be enough for someone to see the logic of my approach, and to then suggest a more effective approach.
The code that declares the class in question is:
class SineDraw extends JPanel implements MouseMotionListener, MouseListener {
// lots of code, including the two segments excerpted below
}
This segment of code overloads the paintComponent of the JPanel so that my data is plotted:
// declare some variables
ArrayList<Double> PeakList = new ArrayList<Double>() // this ArrayList is populated by an extraneous process
visiblePoints = 5000
hstep = getWidth()/visiblePoints //=581/5000 by default, but will change when user resizes window
int numPeaks = PeakList.size();
// scale (y-coordinate) data relative to height of panel
pts = new double[visiblePoints]
for (int i = 0; i < pts.length-1; i++){pts[i]=//data vertical scaled to fill panel;}
// plot the 5000 time-series-data-points within the 581 pixels in x-axis
for (int i = 1; i < visiblePoints; i++) {
int x1 = (int) ((i - 1) * hstep);
int x2 = (int) (i * hstep);
int y1 = (int)pts[i - 1];
int y2 = (int)pts[i];
g2.drawLine(x1, y1, x2, y2);
}
// plot a rectangle for each of the local peaks
for(int m=0;m<=(numPeaks-1);m++){
if(i==(int)(PeakList.get(m)){
int currentVal = (int)pts[(int)(PeakList.get(m)];
g2.drawRect((int)(PeakList.get(m), currentVal, 6, 6);
}
}
This section of code is for handling the right-clicking of the mouse:
public void mousePressed(MouseEvent e){
// check to see if right mouse button was clicked
boolean jones = (e.getModifiers()&InputEvent.BUTTON3_MASK)==InputEvent.BUTTON3_MASK;
if(jones==true){
// test the value returned as x-coordinate when user right-clicks (code always underestimates x-coordinate of local peaks by this test)
double ReverseHstep = visiblePoints/getWidth();
int getX_ConvertedTo_i = (int) (e.getX()*ReverseHstep);
System.out.println("getX_ConvertedTo_i is: "+getX_ConvertedTo_i );
// check to see if peaklist contains a value within the x-coordinates of the user-selected-rectangle
if(PeakList.contains((double)(e.getX()-3))
||PeakList.contains((double)(e.getX()-2))
||PeakList.contains((double)(e.getX()-1))
||PeakList.contains((double)(e.getX()))
||PeakList.contains((double)(e.getX()+1))
||PeakList.contains((double)(e.getX()+2))
||PeakList.contains((double)(e.getX()+3))
){
// handling code will go here, but for now it is a print test that never succeeds because x-coordinate is always underestimated
System.out.println("You just selected a peak!");
}
}
repaint();
}
I suggest you create objects (in this case Rectangles) for each thing you want to be clickable. Here is an over-simplified example of how you can make something you draw clickable. The key thing to take away from this is the mouseClicked method which will display a dialog only if the mouse clicked within the rectangle.
One tricky point is that I wasn't able to figure out how to make the rectangle filled in with color without drawing another rectangle over it. I'll leave that one for you ;-)
public class Canvas extends JPanel implements MouseListener{
private Rectangle rect = new Rectangle(100,100);
public Canvas(){
this.addMouseListener(this);
rect.setSize(100, 100);
}
#Override
public void paintComponent(Graphics g){
g.setClip(rect);
g.setColor(Color.RED);
g.fillRect(0, 0, 100, 100);
}
#Override
public void mouseClicked(MouseEvent e){
if(rect.contains(e.getPoint())){
JOptionPane.showConfirmDialog(this, "Click!");
}
}
// The rest of the MouseListener methods have been cut out
public static void main(String[] a){
JFrame frame = new JFrame("Canvas Thingy");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0, 0, 300, 300);
frame.add(new Canvas());
frame.setVisible(true);
}
}
As in wen you run any output in a frame, every time you run the program it pops on a different position on the screen?
You can use the setLocation(int, int) of JFrame to locate a JFrame in a new location.
So, put this in the frame's constructor and use Random to generate a random location, and your frame will pop up in a random location every time.
Another option would be to override the setVisible(boolean) method of the JFrame.
public void setVisible(boolean visible){
super.setVisible(visible);
if (visible) {
Random r = new Random();
// Find the screen size
Toolkit tk = Toolkit.getDefaultToolkit();
Dimension d = tk.getScreenSize();
// randomize new location taking into account
// the screen size, and current size of the window
int x = r.nextInt(d.x - getWidth());
int y = r.nextInt(d.y - getHeight());
setLocation(x, y);
}
}
The code located inside the if (visible) block could be moved inside the constructor. The getWidth() and getHieght() methods may not return the correct values that you expect though.
Use java.util.Random's nextInt(int) along with JFrame.setLocation(int, int).
For example,
frame.setLocation(random.nextInt(500), random.nextInt(500));
If you receive an error such as Cannot make a static reference to the non-static method nextInt(int) from the type Random
you can use the alternative code, frame.setLocation((int)Math.random(), (int)Math.random());
Hope this helps!