Panel.repaint() doesn't seem to be refreshing panel - java

I'm having some issues repainting a JPanel on my GUI with default values.
The code I'm using right now is below, again, I'm not used to, nor really knowledgeable about java code, so forgive me for making rookie mistakes:
private void btnResetActionPerformed(java.awt.event.ActionEvent evt) {
...
pnlWagens1 = new pnlWagens();
UpdateGUI();
}
private void UpdateGUI(){
pnlWagens1.repaint();
}
So far I've tried the above code, as well as setting the JPanel to null, repainting, inserting a new instance of the panel, repainting again.
Nothing so far has been fruitful, as in the end, I'm still stuck with the old panel (and it's values) being shown on my GUI.
Basically, I make a panel with a green background initially, make the background red, then resetting the panel to have a green background again. However in the end, after hitting Reset, it still shows the old panel with the red background.
Any insight as to what I may be doing wrong/overlooking would be greatly appreciated.

Assuming this is all the relevant code (and that UpdateGUI doesn't use add or remove with the panel reference you have there), then changing what object pnlWagens1 refers to in your local class won't change other references that still refer to the old object. The old object pnlWagens1 is still referenced by Swing in another location, from when you originally called add on some container.
What you need to do is to remove pnlWagens1 from the container, change pnlWagens1 like you are doing now, readd pnlWagens1 to the container, and call then call both revalidate() and repaint() on the container.

Related

Why do I have to use setvisible() on my JFrame when I change components?

So for the sake of simplicity I set up a little test code just to figure out this problem. Basically I have a JFrame and I added 'this' to it (I just extended my main class from JComponent to save time). this component fills in a red background. Then I have it sleep for 2 seconds and then type this.
f.remove(this);
thing t = new thing();
f.add(t);
f.setVisible(true);
f being my JFrame object and 'thing' is just another class extending JComponent that paints a blue background..
when I comment out setvisible() it no longer changes to blue.. I've tried using t.setVisible(true) but it seems I have to make the frame visible again, not the component
does anyone know why I have to call that... or if there is another way to change components within a single frame?
"Basically I have a JFrame and I added 'this' to it (I just extended my main class from JComponent to save time). this component fills in a red background. Then I have it sleep for 2 seconds and then type this."
Don't "sleep" your program. Instead use a java.swing.Timer to perform repeated tasks on the GUI or for animation. See more at How to Use Swing Timers. You can see a bunch of Timer examples here and here and here and here and here
Instead of trying to add and remove panels look into using a CardLayout which allows you to switch between views. It will help you avoid a lot of problems that come with with adding and removing components/containers. See more at How to Use CardLayout. Also see a simple example here.
To answer your main question, whenever you remove and add components from your frame, you need to revalidate() it. setVisible() takes care of that for you.
Side Note
Seems like a lot adding an removing background panels) just to change the background. Why not just setBackround()? You can switch colors with the use of the Timer
Calling setVisible(true) makes the frame appear onscreen. Sometimes you might see the show method used instead. The two usages are equivalent, but we use setVisible(true) for consistency's sake.

Limit JButton repaint to state changes?

After what I learned from my previous question, I would like to use a texture to paint the text on an extended JButton while it's being pressed. The first step was setting up the button's ChangeListener and stateChanged method; I have these working and can set the foreground color in the method, so that the text will be one color while the button's pressed and another while not.
Building on this, I replaced the setForeground call with the drawString code I used for my toggleButtons. It works, but immediately after the text is drawn it's overwritten by the button being automatically repainted. I tried throwing the code in a "while (model.isPressed())" loop, but that had some pretty terrible results (system hang). How would I go about manually repainting my button, so that it's only redrawn during the stateChanged method?
It seems to me that you are going the wrong way to change the look of your button. I think it would be easier for you to create a class that would handle the look and feel of your button, instead of manually handling the drawing parameters of your button inside the button's code. Blocking the repaint() calls isn't really the way to go I believe in your case.
I would personally create my own ButtonUI implementation that would handle all the paint rules (foreground color based on button state for instance), then I would call the setUI on the button, specifying an instance of this new ButtonUI as a parameter. If you don't want to handle all the drawing stuff, you can always use your new class as a proxy to the button's already existing UI handler (through JButton's getUI() method), and make changes only where you need them (I haven't tested it myself, but I'm pretty sure it would work just fine).
Of course, this represents more coding for you, but it would localize your look and feel handling in a single class, and it would fit in Swing's way of working. There are a few resources on the web to get you started (here, here and here).

Who is calling paintComponent?

For some reason, my paintComponent(Graphics g) method is being called infinitely. I can't seem to tell who is calling it, even if I dump a StackTrace in the call (it's an event that's dispatched and handled).
Are there any easy ways to find out who's triggering the event?
Update: I've found the cause and I now understand the reason. Whoever answers it correctly will get the answer to the question.
Here is the code that's causing the issue:
#Override
public void paintComponent(Graphics g)
{
myJButton.setIcon(ResourceLoader.getImageIconWithLocale(MY_BUTTON_IMAGE));
super.paintComponent(g);
}
FYI: It's a really tricky one!! It's not obvious by looking at the code. I made an assumption that was wrong.
I don't know which component this is, but setting an icon on a button from within a paint routine is a bad idea. It will definitely cause the button to be repainted. If the button is a child of your component then setting the button invalidate the component too causing an infinite loop.
Set the icon somewhere else such as where the dialog / window is set up initially.
The setIcon(ImageIcon) will revalidate and repaint itself ONLY if the ImageIcon is another instance.
When working with Locales, most people are use to the ResourceBundle, which returns Strings, which in turn are immutable. Therefore setting the text over and over doesn't matter.
However, in this case, the ResourceLoader (custom class) returned a new instance of an ImageIcon. Sure it was the same Image, but it was another instance. And if you decompile the code, you'll see that setIcon (at least for JButtons), it will repaint and revalidate if newIcon != oldIcon.
The solution was to use a HashMap in the ResourceLoader, this way it saves from loading the images more than once since most of the images are used very frequently (might as well reuse the instances if you can). Turns out that overall this quick adjustment also saved a decent amount of overall memory consumption as an added bonus.
Are you calling repaint() anywhere? Also, when a window becomes visible (uncovered or deminimized) or is resized, the "system" automatically calls the paintComponent() method for all areas of the screen that have to be redrawn.
The problem is that you are setting the icon in the paintComponent() method. You should never set a property in this method.
Swing components are smart enough to repaint themselves whenever a property changes. In this case you have the problem of the component repainting itself because the Icon changes, but you are also rereading the Icon every time the component repaints itself which is also not very efficient.

Java Swing: dispose() a JFrame does not clear its controls

I have a closeWindow() method which uses dispose() for the current JFrame to close down. When I show the window again, the controls (textboxes, lists, tables etc.) still have their previous values in place that were there when I dispose():d the frame... Why is that? Is there another way to completley close and clear a frame?
This is the code that another JFrame uses to show the other window, am I doing something wrong here?
#Action
public void showAddProductToOrderView() {
if (addProductToOrderView == null) addProductToOrderView = new AddProductToOrderView(this);
addProductToOrderView.setVisible(true);
}
Disposing a window will not clear its child text components. Dispose will release native resources. The javadoc for java.awt.Window also states:
The Window and its subcomponents can be made displayable again by rebuilding the native resources with a subsequent call to pack or show. The states of the recreated Window and its subcomponents will be identical to the states of these objects at the point where the Window was disposed (not accounting for additional modifications between those actions).
As suggested by others, create a new instance each time instead. If that's to expensive I believe your best option is to clear sub components when the view becomes visible, e.g. by overriding setVisible.
EDIT:
Remove the null check to create a new frame each time.
#Action
public void showAddProductToOrderView() {
addProductToOrderView = new AddProductToOrderView(this);
addProductToOrderView.setVisible(true);
}
I don't know about the rest of your code, if there's something else depending on the frame being reused. For example, if you have attached listeners, ensure they are unregistered to not leak them.
The simplest thing to do would be to re-create the whole frame (using its constructor) before using show() to show it again. That will give you a whole new set of components, assuming that the constructor creates and places them.

How do I dynamically add Panels to other panels at runtime in Java?

I'm trying to get into java again (it's been a few years). I never really did any GUI coding in java. I've been using Netbeans to get started with this.
When using winforms in C# at work I use a usercontrols to build parts of my UI and add them to forms dynamically.
I've been trying to use JPanels like usercontrols in C#. I created a JPanel form called BlurbEditor. This has a few simple controls on it. I am trying to add it to another panel at run time on a button event.
Here is the code that I thought would work:
mainPanel.add(new BlurbEditor());
mainPanel.revalidate();
//I've also tried all possible combinations of these too
//mainPanel.repaint();
//mainPanel.validate();
This unfortunately is not working. What am I doing wrong?
I figured it out. The comments under the accepted answer here explain it:
Dynamically added JTable not displaying
Basically I just added the following before the mainPanel.add()
mainPanel.setLayout(new java.awt.BorderLayout());
Swing/AWT components generally have to have a layout before you add things to them - otherwise the UI won't know where to place the subcomponents.
BFreeman has suggested BorderLayout which is one of the easiest ones to use and allows you to 'glue' things to the top, bottom, left, right or center of the parent.
There are others such as FlowLayout which is like a textarea - it adds components left-to-right at the top of the parent and wraps onto a new row when it gets to the end.
The GridBagLayout which has always been notorious for being impossible to figure out, but does give you nearly all the control you would need. A bit like those HTML tables we used to see with bizarre combinations of rowspan, colspan, width and height attributes - which never seemed to look quite how you wanted them.
I was dealing with similar issue, I wanted to change the panel contained in a panel on runtime
After some testing, retesting and a lot of failing my pseudo-algorithm is this:
parentPanel : contains the panel we want to remove
childPanel : panel we want to switch
parentPanelLayout : the layout of parentPanel
editParentLayout() : builds parentPanel with different childPanel and NEW parentPanelLayout every time
parentPanel.remove(childPanel);
editParentLayout();
parentPanel.revalidate();
parentPanel.repaint();
As with all swing code, don't forget to call any gui update within event dispatch thread. See this for why you must do updates like this
// Do long running calculations and other stuff outside the event dispatch thread
while (! finished )
calculate();
SwingUtilities.invokeLater(new Runnable(){
public void run() {
// update gui here
}
}
mainPanel.add(new BlurbEditor());
mainPanel.validate();
mainPanel.repaint();
Try mainPanel.invalidate() and then if necessary, mainPanel.validate(). It also might be worth checking that you're doing this all in the event dispatch thread, otherwise your results will be spotty and (generally) non-deterministic.

Categories

Resources