I have a SWT application which displays and sorts image files by renaming the file. Scruffy I know, but the sorted-by-name files are the input for a later step that I cannot change.
So far I have the UI almost working but the initial image at startup does not generate a paint event, so the Canvas is blank. If I minimally resize the window, it immediately appears correctly. I am trying (perhaps incorrectly) to generate the event explicitly using the notifyListeners() method of Canvas which needs to be passed a PaintEvent and I am stuck on how to instantiate one.
What is the correct way to force this initial event to be generated?
You don't have to explicitly fire a PaintEvent. Instead use one, or combination, of the below options:
layout() marks forces the repositioning of all composite-children.
This will become visible on next repaint, which will be done
somewhere in the future, when composite's screen-area will be redrawn
redraw() marks the widget an invalidated. On next
redraw-system-action this area will be repainted.
update() forces all outstanding redraw() requests to be completed
NOW.
Related
At times, certain UI elements that have a hover style will not render at all and a white box is left in it's place. This only happens after I resize the application window and when the UI element is completely outside of the original bounds of the application window. The button shown in the images below also does not immediately render correctly after removing the mouse pointer from the hover position, so the issue likely would occur whenever the button needs to be repainted.
"Device Logging" button is being hovered by the mouse, before resizing the window.
After resizing the window. Both the "Device Logging" and "Misc Tests" buttons are 100% outside of the original bounds of the window. The "Cloud Server Migration" button however is still rendering correctly.
I have set styles, but removing them has no effect. The issue only seems to appear when there is other processing taking place, such as running the firmware update function. That tells me that there may be something taking up UI time, but I would have expected that to affect every UI element, not just certain ones.
One other note, the UI was converted from Swing to JavaFX, so all of the threading did not include the use of Task or Platform.runlater(). I have since made sure all UI updates are using Platform.runlater(), but I have not yet converted all of the original threads that don't update the UI to Tasks. Below I am including the framework of running a firmware update.
Edit: Was able to reproduce the issue without starting a firmware update, so I don't think it has anything to do with processing blocking UI rendering. The issue occurred only after using some of the UI. As such I removed the code that was posted above. This leads me to believe it has more to do with the actual layout of the UI.
I believe I have figured out the issue. I use a ListView to hold an Object and a cellfactory to render each of the cells with a custom UI. When populating the list with items, additional threads are spawned to retrieve information for each Object within the cell. The variables associated with the Object are bound to a view property within the custom UI. I was not using Platform.runlater() to update these properties with the new information. After updating the sets to runlater, the issue appears to have been fixed.
I'm making a map editor using java swing for my tile based java game. the swing application has two major components, the "upper" component is the game map preview, and the "lower" component is modifyable properties of the map, like its height and width.
Currently the user types in to a jtextfield for the map width, then I use a change listener to set that value to the GameMap object. The GameMap object when changed fires a notification event to GameMapListeners, the primary listener it has is the preview display of the map inside the swing application.
This lets the user change the map width and instnatly see the results in a preview pane.
Now I want to go to the other way. I want the user to be able to click and drag the edges of the map in the preview pane, but then the results need to then be sent to the properties panel so it shows the updated width value.
This is where the problem is, if I update the jtextfield it'll fire a change event, which would update the GameMap and update the preview display, and then that would fire an event that changes the jtextfield again (so on and on until the program crashes due to stack overflow)
Are there any kind of design patterns i could use instead, or is there some common way to solve this issue?
In this type of case, you have at least two choices...
You Could
Remove the listener to the other component when you want to trigger a change, adding it back after you've raised the event...
You Could
Change the state of a flag to indicate that you should ignore any changes that might come in, resetting after you're raised the event...
Which one you choose will depend on how much code you want to add and how readily available the reference to the listeners in question are (ie, if you don't have a reference to the listener you want to remove, it's kind of hard to implement)
If I update the jtextfield it'll fire a change event, which would update the GameMap and update the preview display, and then that would fire an event that changes the jtextfield again (so on and on until the program crashes due to stack overflow).
When you have a situation like this, you can temporarily remove event listeners, fire the change event, and add the event listeners back. Yes, this is as much of a pain as it sounds, but it's a good way to prevent the stack overflow.
You can see a detailed explanation as well as a working example of managing event listeners in my Sudoku Solver Swing GUI article.
You can use action events for a JTextField. Action events don't trigger when you change the component programmatically.
I've a GUI based on Eclipse SWT/RCP . When that GUI is in Full Size and I minimize it and then maximize it , I see a dark/black over the Ui for a second or more and then it becomes normal. I want to know, what might be the reason for same
Following is the screenshot -
This usually indicates that you have a code that runs longer than it should on an event listener and the paint events are not dispatched until that code is done. Hence you see the black areas until they are dispatched and painted. I recommend checking the logic on listeners especially for resize and focus events if you have any.
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).
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.