Force call to paintComponent - java

I realise this code looks, pointless, I've just got rid of the irrelevent stuff to show the structure
class Drawer extends JComponent {
public Drawer(int[] data) {
System.out.println("drawer");
for(int x = 0; x < data.length; x++){}
//work out what to draw
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("drawerpC"); //check to see if it is called
//draw stuff
}
}
In a separate file, a new instance of Drawer is called regularly. Every time it is called, data is different, and so every time Drawer is called, paintComponent needs to be called.
I have this code in that other file:
Drawer d = new Drawer(data);
myGUI.con.add(d); //myGUI.con is a previously set up container
repaint() is not causing paintComponent to be called (otherwise you'd see the stdout), so how can I force paintComponent to be called for every calling to Drawer?

Store the int[] as a class attribute. Move //work out what to draw into paintComponent(Graphics).

Calling repaint will have no effect until the component is part of the display hierarchy. It can't possibly be part of a hierarchy while the constructor is still executing.
One option is to add a HierarchyListener to the root of your display hierarchy and do the repaint there. However, it's far from clear to me what you're trying to accomplish and this might not be the best approach.

Related

setLocation() and setBounds() method for JButton not working in specific cases

I found similar questions on this forum, but they are not exactly my problem. I have a JPanel with absolute layout and on that panel, I have two JButtons. One is called swapButton, which swaps position of two buttons on the same panel and another is openButton, which opens an image do some processing with that image and with some buttons on the same panel and then calls swapButton.doClick().
Code for action performed by openButton:
private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {
FileDialog filedialog = new FileDialog(GameFrame.this,"Open File",FileDialog.LOAD);
filedialog.setVisible(true);
try{
if(filedialog.getFile() != null){
filename = filedialog.getDirectory() + filedialog.getFile();
file = new File(filename);
File deleteFile = new File(defaultPath.toString());
deleteFile.delete();
Files.copy(file.toPath(),defaultPath);
file = new File(defaultPath.toString());
imageSelected = true;
newGame = true;
cropImage();
setImage();
}
}
catch(IOException e){}
if(imageSelected){
setCombination();
swapButton.doClick();
moves = 0;
msgLabel.setText("");
}
}
Code for action performed by swapButton:
private void swapButtonActionPerformed(java.awt.event.ActionEvent evt) {
int n = Integer.valueOf(numText.getText()); //gets value from a text area
swapButton(n);
}
Code for swapButton method:
void swapButton(int i)
{
javax.swing.JButton button1 = buttonList[i], button2 = emptyButton;
int x1 = button1.getX(), y1 = button1.getY();
int x2 = button2.getX(), y2 = button2.getY();
button1.setLocation(x2, y2);
button2.setLocation(x1, y1);
int p1 = pos[i], p2 = pos[8];
pos[i] = p2;
pos[8] = p1;
arr[p1] = 8;
arr[p2] = i;
moves++;
}
I coded the action performed by swapButton in a seperate method for a purpose.
The problem is, when I click on openButton, all actions of that button works perfectly and swapButton.doClick() is also called, but the location of the buttons in my JPanel remains the same instead of calling setLocation() method in swapButton() method. But when I click on swapButton, all action in swapButton() method works fine. I also tried calling swapButton.doClick() from other area of the code and it works fine.
I printed the locations of the buttons after calling setLocation() method in swapButton() method using getLocation() method and it shows new locations for those buttons, but there are no changes in locations of those buttons in my JFrame. I also tried using setBounds() and getBounds() method and got the same result.
Is it some bug? Or something wrong done by me?
First of all, absolute layout means no layout manager or null layout manager. This is absolutely not recommended. For any beginning or intermediate Swing programmers out there, you should essentially never use absolute layout. If I were doing this I might create my own custom implementation of the java.awt.LayoutManager interface, and give that implementation a swap() method. That would keep all the location-swapping stuff encapsulated in my custom layout manager. But that's not what you asked.
It's hard to answer your question without more details, but is there a reason you need to call the swapButton's doClick() method? You would call that if it were important for the user to see the button appear to be pushed on the screen. [doClick()'s default on-screen push length is 68 milliseconds, btw, during which the EDT* will be frozen.] If you're only concerned that swapButton's ActionListener method gets invoked, then it may work better to simply call that method directly. That way, the openButton stuff does not depend on the timing of when swapButton's listeners are registered and such.
If you replace swapButton.doClick() with swapButtonActionPerformed() does it work any better?
Something else to watch for is that you're doing all this location swapping stuff on the event dispatch thread (EDT). From your description there's no indication that you are not running on the EDT, but we can't tell for sure without seeing the rest of your code. Hence the usefulness of an SSCCE.
*footnote: unless you're not calling it from the EDT, which is its own problem

How do I properly paint to a frame/panel?

I've tried many variations of everything at the bottom of this class and so far nothing works. Occasionally an edit will cause the print statement to work, but the window just always opens at a size that isn't even the one I set it up and stays blank. I don't know what's wrong with it. I'm trying to print 1024 rectangles on my window with a pause inbetween each print. The values are right, they're just not getting painted for some reason. Changing the method to paintComponent doesn't seem to do much either. The code is long, so here's a pastebin: http://pastebin.com/ridipz3X. The important stuff is at the end though:
JFrame frm = new TestEnvironment();
frm.setSize(1152, 1152);
frm.setVisible(true);
JPanel panel = new JPanel();
frm.add(panel);
t = 0;
i = 0;
while (t < x - 1) {
panel.repaint();
j++;
t++;
Thread.sleep(10000);
}
} catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
public void paint(Graphics g) {
g.setColor(Color.black);
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(getForeground());
try {
for (int h = 0; h < 1152; h++) {
g.drawRect(h, 0, (int) (((ampArray[h][j]) / maxFreq) * 1152),
1);
g.fillRect(h, 0, (int) (((ampArray[h][j]) / maxFreq) * 1152),
1);
System.out.println(ampArray[h][j]);
}
} finally {
g.dispose();
}
}
}
Thanks
Painting is typically done from within the paintComponent method of a component that extends from JComponent, typically a JPanel, depending on your needs.
You should refrain from overriding paint of top level containers like JFrame for a number of reasons, including, they are not double buffered, you will end up painting under the window decorations, Swing windows contain a number of layered components which make up the viewable content of a window, meaning that you will either paint over or under this content, which just gets messy.
You should never dispose of Graphics context that you did not create yourself.
Swing is a single threaded environment, that is, anything that blocks the thread (such as Thread.sleep, will prevent it from process new repaint requests and events, making it look like you program has stopped.
Swing is also not thread safe. This means that you are required to ensure that all updates and interactions with the UI are done from within the context of the Event Dispatching Thread.
Animation is typically achieved through the use of a javax.swing.Timer or SwingWorker depending on the complexity of the animation. You can use a Thread, but it complicates the issues as you will be required to ensure that all updates to the UI (directly or otherwise) are done from within the context of the EDT manually.
Take a look at:
Performing Custom Painting
Painting in AWT and Swing
Concurrency in Swing

Why do statements get executed more than once in paint or paintComponent methods?

I am trying to draw and paint some geometric shapes based on some calculations inside the paint() or paintComponent() methods. However, I realized that the printing and other calculation statements inside paint() or paintComponent() are executed 2 or sometimes 3 times. For example the print statement in the following code is executed twice and the word "help" is printed twice in the console:
public class Skeleton extends JPanel {
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.drawOval(50, 50, 100, 100);
System.out.println("help");
}
and then in the console the printed part is like this:
help
help
and here is my main() method
public static void main(String[] args) {
JFrame frame = new JFrame("Java 2D Skeleton");
frame.add(new Skeleton());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(870, 890);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
What is worse is that, if I have a class public variable and I am increasing its value by 1 within the paint() method. This results in having the value increased by 2.
I have read somewhere in this website such that the method paint() automatically invokes three other methods, which I thing they are causing this problem.
Also I have tried some suggested solution on another website to override the method paintComponent() instead of the method paint(). However I still have the same problem.
Please help me fix it.
You are right to override paintComponent instead of paint. I think the issue here is that paintComponent should do one thing, paint your component. Any number of things can cause a call to repaint() which will call your paintComponent, so it's not really guaranteed when and how often this method will execute. Doing calculations and keeping track of variables should probably be a part of a separate model class that your component can look at to know what to draw.
This question has probably been forgotten but I stumbled upon it and would like to help out anyone else who does too. The solution I found was to use JApplet's init() method. There you can do all the calculations you need. Then, if you want, you can also create a timer that responds at a specified interval to call repaint() and do iteration-ish work. That way, you can leave everything except the actual drawing code out of paint. It would look something like this:
public void init()
{
//do calculations here
javax.swing.Timer timer = new javax.swing.Timer(1000 / frameRate, new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
//this is called every so often. Can link to update loops or be an
//update loop itself.
repaint();
}
} );
timer.start();
}
public void paint(Graphics g)
{
//All the actual drawing code for the shapes goes here.
}

Should I implement actions inside the methods of an InputListener object?

I am making a button using MouseOverArea. After some trial and error, I realized I can override the methods in InputListener to do particular actions when an input event is notified.
For example, do things when mouse left button is pressed while cursor is over the component.
#Override
public void mousePressed(int button, int mx, int my) {
if (isMouseOver() && button == Input.MOUSE_LEFT_BUTTON) {
// Some magic happens
}
}
However, I will not able to do things like changing current game state because no Game object around. I know there are many ways to solve this problem, but I would like to know what is the Slick way to do this.
Are these methods suitable for such behavior ?
One way to modify game states is to use boolean states; Which are boolean variables that hold the state of the game or player. For example:
boolean isMovingUp, isMovingLeft, isMovingRight, isMovingDown;
You can then set these to true/false depending on what mouse or keyboard event takes place and your game class then read these variables, like so:
if (isMovingUp) {
// do something
isMovingUp = !isMovingUp;
}
Hope that helps!

How does JButton implement its icons?

I'm trying to understand how Swings JButton/AbstractButton implements the painting of its icons (defaultIcon, disabledIcon, pressedIcon, etc.).
I have found the fields/getters/setters for said icons in AbstractButton, but apparently the assorted paint methods are inherited directly from JComponent. This begs the question how the icons are ever painted!? Obviously they are, but I could not find the code that does it.
Paiting of components in Swing is made by the Look-n-Feel. So if you want to find how the icon of a button is painted simply look the method paintIcon of the class BasicButtonUI. But each Look-n-Feel you use can provide different painting.
The icon in JButton is painted by the UI Class. And the UI class is defined by the Look and Feel. It is an implementation of javax.swing.plaf.ButtonUI.
JComponent.paint method get the ui property from the instance and invoke its update method (and is where the icon is painted). The UI of the instance is acquired by the UIManager.
You can se the paint method on Open JDK BasicButonUI
I hope I understand your question: are you trying to understand how does an icon get painted on an JButton? Take a look at the paint method from JComponent (its super super class). I'll add comments to make it easier to explain:
public void paint(Graphics g) {
boolean shouldClearPaintFlags = false;
//Check the size of the component: don't draw anything with a negative width or height!
if ((getWidth() <= 0) || (getHeight() <= 0)) {
return;
}
//Create new Graphics objects (why? to create the images)
Graphics componentGraphics = getComponentGraphics(g);
Graphics co = componentGraphics.create();
try {
RepaintManager repaintManager = RepaintManager.currentManager(this);
//Initialize a RepaintManager (JavaDoc says: "This class manages repaint requests, allowing the number of repaints to be minimized")
//Create a rectangle at the size of a graphics object
Rectangle clipRect = co.getClipBounds();
int clipX;
int clipY;
int clipW;
int clipH;
//If the rectangle is null, then give it default values
if (clipRect == null) {
clipX = clipY = 0;
clipW = getWidth();
clipH = getHeight();
} else { //otherwise, use its coordinates
clipX = clipRect.x;
clipY = clipRect.y;
clipW = clipRect.width;
clipH = clipRect.height;
}
//Ajust the clip widths and heights
if(clipW > getWidth()) {
clipW = getWidth();
}
if(clipH > getHeight()) {
clipH = getHeight();
}
//If your Component is placed on a JComponent (or extended class), then make adjustments
if(getParent() != null && !(getParent() instanceof JComponent)) {
adjustPaintFlags();
shouldClearPaintFlags = true;
}
//Check if the component is printing (private flag IS_PRINTING)
int bw,bh;
boolean printing = getFlag(IS_PRINTING);
//If the component is not printing its contents, and if the repain manager is double buffered, AND if not ancestor (subclass) is buffering AND if the components is buffered....
//JavaDoc says for RepaintManager.isDoubleBufferingEnabled(): "Returns true if this RepaintManager is double buffered. The default value for this property may vary from platform to platform."
if(!printing && repaintManager.isDoubleBufferingEnabled() &&
!getFlag(ANCESTOR_USING_BUFFER) && isDoubleBuffered()) {
//... then start painting the Graphics
repaintManager.beginPaint();
try {
repaintManager.paint(this, this, co, clipX, clipY, clipW, clipH);
} finally {
repaintManager.endPaint();
}
//if there is an exception, a try/finally is required to avoid the RepaintManager being "left in a state in which the screen is not updated" (JavaDoc)
}
else {
// Will ocassionaly happen in 1.2, especially when printing.
if (clipRect == null) {
co.setClip(clipX, clipY, clipW, clipH);
}
//Checks if the rectangle at the specified coordinates if obscured
if (!rectangleIsObscured(clipX,clipY,clipW,clipH)) {
//Then paint the graphics (or print if printing is true)
if (!printing) {
paintComponent(co);
paintBorder(co);
} else {
printComponent(co);
printBorder(co);
}
}
//Also paint the children (eg: a JPanel has a JLabel and a JButton as children if you add them to the panel) (or print if printing is true)
if (!printing) {
paintChildren(co);
} else {
printChildren(co);
}
}
} finally {
//Clean up!!
co.dispose();
if(shouldClearPaintFlags) {
setFlag(ANCESTOR_USING_BUFFER,false);
setFlag(IS_PAINTING_TILE,false);
setFlag(IS_PRINTING,false);
setFlag(IS_PRINTING_ALL,false);
}
}
}
In other words, there is a lot of code involved in painting Graphics objects, but the steps are pretty simple once you've analyzed the code:
Create new Graphics objects from the one passed in parameter;
Initialize a RepaintManager for repaint requests;
Check if the graphics can be painted, and do so if possible;
Finalize by repainting the children;
You're done!
If you want to know more on how the painting process is applied, then according to Oracle's Java documentation:
In Swing, painting begins with the paint method, which then invokes paintComponent, paintBorder, and paintChildren. The system will invoke this automatically when a component is first painted, is resized, or becomes exposed after being hidden by another window.
Programatic repaints are accomplished by invoking a component's repaint method; do not invoke its paintComponent directly. Invoking repaint causes the painting subsystem to take the necessary steps to ensure that your paintComponent method is invoked at an appropriate time.
You can invoke repaint multiple times from within the same event handler, but Swing will take that information and repaint the component in just one operation.
For components with a UI Delegate, you should pass the Graphics paramater with the line super.paintComponent(g) as the first line of code in your paintComponent override. If you do not, then your component will be responsible for manually painting its background. You can experiment with this by commenting out that line and recompiling to see that the background is no longer painted.
I took the code from here.
I hope I was able to help you,
Cheers

Categories

Resources