I've read through lots of the threads on paintComponent here, most of which making the point that it either is never or almost never necessary (or possible) to choose when paintComponent is called.
In my program, however, sometimes (only sometimes) paintComponent gets called before some of the objects it needs to paint have finished initializing or even sometimes before they've been created, triggering warnings- JOptionPane pop-ups, which surprisingly do not show any of the text they were hard-coded to display in their "message" area. I've read in other places that it's something to do with the EDT, and I've looked into some parts of that but I'm just getting confused. If the main purpose of the EDT is to update the gui, and by default pretty much everything will run in the EDT, then could I tell the program to run all the initialization and update functions in a different thread(s), which I somehow forcibly make run before the EDT runs?
What I'd ideally like to have happen is for paintComponent to wait until a certain point in my code to be run (after a bunch of update functions, regardless of what happens to the screen. After it does get called, it is followed by a pause in which relatively little is going on ( I had been using Thread.sleep() inside a while loop ) and which lasts until the user clicks something - at which point all the necessary functions are run again, followed by paintComponent afterwards, then the sleep() while loop, etc.
From what I understand, I think what I want isn't really possible, so my question is: Do you guys have any ideas of how to get around this?
EDIT:
So essentially the program is a college course planner, intended to make it easier for someone to plan out by semester all the courses they have to take before graduation, move those courses around (if possible), and see how all the courses are connected (prerequisites and such). When the program starts, it loads the list of necessary courses from a text file, then loads info about each course from a bunch of individual text files, and arranges them according to their prerequisites. Courses with no prerequisites go in the first semester, courses whose prerequisites have all been added to the first semester get added to the second, and so on until all the courses have been added. When paintComponent runs, it calls a function that assume all of each course's prerequisites exist on the schedule, and if it finds otherwise, it throws an error and displays a JOptionPane message box. When this happens during a normal run of the program (like if I manually add a course before adding its prerequisites), that all works and displays correctly. But sometimes that message box pops up when only some of the courses have been loaded (meaning control is still in the main constructor) and when it does so, the actual string message doesn't show up - only the actual pane, title and ok button do. Heres the line where I display the error box, so you can know that I'm not trying to display a string variable which has the potential of being empty.
JOptionPane.showMessageDialog(this,
"Course couldn't be loaded, partially >loaded\ncourses have been removed.",
"Error",
JOptionPane.OK_OPTION);
It is the "Course couldn't...been removed." part that doesn't get displayed. This is the only JOptionPane I display with the title "Error".
This post mentioned what sounds like the same thing happening, except I'm not using any of the things that poster had to fix. So possibly it's irrelevant but I'll add it just in case. JOptionPane.showMessageDialog() shows but without any message?
But to step back a bit, because that box popped up before all the courses had been added, it means that paintComponent was somehow called in the middle of the relevant JPanel's constructor, before a bunch of things had been initialized. I added a bunch of println() statements to make sure that that is true. Is it normal for that to happen, and if so, is there a way to fix it without simply using Andrew Thompson's advice?
After thinking though it a bit, I think that because the project is 3200 lines long and relies to a huge extent on text files, I'm really not sure how to ( or if I can) make a SSCCE for it..
If any specific pieces would be helpful I'll gladly add those but if this problem isn't clearly some standard issue I'm getting wrong, then I'll just add that flag and keep looking for bugs.
Thanks for your help
Declare a flag as a class attribute. Check it in the paint method. Change it at the end of the initialization.
class XandYandZ extends JComponent {
boolean initializationFinished = false;
public XandYandZ() {
// long initialisation..
initializationFinished = true;
}
public void paintComponent(Graphics g) {
if (!initializationFinished) return;
// .. paint ..
Related
I have a Java program that's using ProcessBuilder to set up some Servers.
I have also made a Form, that displays a JProgressBar, a JLabel and a JTextArea. The Progressbar is set to be indeterminate, since there doesn't seem to be a way for easy calculation of the workload.
The Label is regularly updated to show the User at which step the programm currently is, and the TextArea displays extra information about the current step.
However, when I start the setup, the Window opens and displays nothing. Just a blank white window with a title.
That is until the setup is either done, or when I'm debugging, where it will sometimes actually display something for a short time.
I have tried calling panel.revalidate() together with panel.repaint() everytime I update a property, but this hasn't changed anything. I remember faintly that there's a specific way to update components while the program is doing stuff in the background, but cannot remember how, and wasn't able to find anything helpful so far.
public void shutdownSystems() throws IOException, InterruptedException {
for (String ip : ipArray) {
if (isWindows) builder.command(ipmitool, ip, "ADMIN", "ADMIN", "ipmi", "power", "down");
loadingForm.setProgressInfo("Shutting down System " + ip);
startProcess();
loadingForm.setProgressInfo(streamGobbler.getResult());
refreshLoadingWindow();
}
}
Here's a piece of code to showcase how I'm trying to do it currently. loadingForm refers to the window which is supposed to have it's components updated. startProcess(); is a local method that executes the command set by the ProcessBuilder builder and compiles the output to also add this information to the window. Last but not least, I call refreshLoadingWindow(); which basically just gets the panel of loadingForm and executes .revalidate(); and .repaint();
The main thing that is confusing me is, while I understand that there's probably a different approach to updating GUIs, it doesn't even show the components at all. Not even when first opening the window.
Can anyone tell me what I'm supposed to be doing instead?
For my program I have a JPane that as the game progresses it adds labels to the panel, however the only way I can make the panels show up is by using add(label) then revalidating and vice versa for removing labels.
My problem is that once it gets to the point that I have more than 40 labels on the screen the revalidate has to process too many things, so how can I override the revalidate(), ether works, so that it only revalidates the specific component that was added, and not every component on the screen. I know there is a loop somewhere within the revalidate() method that will run through a loop of all components, but I just can not for the life of me find it. I would like to be able to call revalidate(component-here) or validate (component-here) and have it only update that specific component.
I know there are other ways of writing this program but I am only interested in how to override revalidate() so no "you could have redone your whole code this way which should only take you like 6 hours >.<".
http://www.fileserve.com/file/jFdQ6nv/FINAL_PROJECT.zip a link to my eclipse project, if anyone who wants to help would like to see what im actually talking abouyt
I just tried this example. Adding 1000 text areas only takes a second, and updates are instant. Labels go even faster. You might want to look at something else slowing it down.
Also, you could look at CellRendererPane. It overrides invalidate() to do nothing.
public void invalidate() {}
I wrote a GUI-based Java program that takes 25 screenshots per second and saves them at a user-defined location.
It works pretty well except that it has two problems:
The mouse cursor is missing from the images and I know it will be because BufferedImages do not contain cursor information in them. They have to be added programatically.
The thread that takes screenshots is a daemon thread. So if I close the application, the thread is killed and the PNG image that was being written gets corrupted. I want to avoid that.
Here are the images of my application:
The award-winning, intuitive GUI:
The high-definition images captured look like this:
As you can see from the image the cursor information is being displayed in the console using MouseInfo's static methods.
Please let me know how to solve the above mentioned two problems.
After solving the problem, the images now look like this:
The mouse cursor is missing from the images and I know it will be
because BufferedImages do not contain cursor information in them. They
have to be added programatically.
That is correct, you have to add the cursor afterwards. The reason for this is that a screenshot taken with the Robot class never contains the cursor. Not really because "the BufferedImage doesn't contain mouse info". A BufferedImage is a class that contains a raster of pixels.
The thread that takes screenshots is a daemon thread. So if I close
the application, the thread is killed and the PNG image that was being
written gets corrupted. I want to avoid that.
Simply, in the screenshot thread, use a flag that indicates wether it should continue or not. Keep taking screenshots as long as that boolean is set to true. Make sure to make it non-deamon. So, when you close the application, set the flag to false.
Probably the most easy way to do this is to add a WindowListener:
yourFrame.addWindowListener(new WindowAdapter()
{
public void windowClosed(WindowEvent e)
{
screenshotThread.stopTakingScreenshots(); // This methods set the flag
}
}
Also notice that you are not taking the time it takes to make and save a screenshot in count. You use a fixed sleep of 40 milliseconds, but let's say that it takes 4 milliseconds to take and save the screenshot, then you should sleep for only 36 milliseconds. To time how long it takes to make the screenshot, use System.currentTimeMillis(); before and after your takeShot() method and make the difference.
Hello? anyone had a problem like: cursor blinking in more than one field at a time?
In my case the following happens: When you double click on a field JTextField, opens a JDialog, so
after closing this, the focus is directed back to the field clicked before opening the screen.
What happens is that after performing this action, two fields are flashing at the same time (usually the first field
screen, as well as the field in which efetuei double click).
This medium is random, there are cases in which it does not occur.
When debugging the inner class Handler, contained within the class DefaultCaret more specifically the actionPerformed method, realized
that: time is a field, and time is another, which are precisely the fields that are flashing (q seems obvious I know). but they are
the own inner classes of Java that are calling the method.
When passing over the field using the Tab, the cursor false, vanishes.
I'm using JDK 6
I returned the focus within the invokeLater(), but not solved. Now both synchronized flash
The first JComponent focusable is one of the fields that flashing improperly
I'm using my own FocusTraversalPolicy, does that may be influencing? The funny thing is that there is no treatment particularly strange about my class.
I noticed that the standard Java class, using a method within the Syncronized getFirstComponent(), but added the same control, but still is not ok
Actually it's Focus issue for me.
Normally when JTextComponent looses Focus setCaretVisible(false) / setSelectionVisible(false) is called and when Focus gained opposite thing happens.
After closing JDialog try to return Focus inside invokeLater(). Also check what's the first focusable JComponent in the JDialog's parent.
This situation occurs because the project I'm developing is quite large, so do not get small examples of implementation
The project has many components, Tables and Container's, which require focus through at the same time.
It turns out that Swing, put in a queue for execution, a lot of threads, and then dispatching them going, and while he did not finish running it, you can cram grabFocus() or requestFocus(), which does not cry, the first he has to finish everything and then run my request focus.
Resolved palliatively this situation, using the Swing SwingUtilities.invokeLater(...);
Thanks for the tips.
So this may seem strange, but I am trying to create a very basic game that works somewhat like what an older RPG game may have as the interface (think choosing attacks from a list (ex: Pokemon)).
Right now I have a class that extends JFrame, and it contains private variables of three panels: one for displaying the sprites at the top 75% of the screen, and the other two are the ones I wish to display text on (one for announcements like, "CRITICAL HIT" and the other for the selectable choices). The second of the text boxes would only be visible sometimes, but that is irrelevant.
Can anybody start me off or lend me a hand? I am finding many way but none that seem to work for my needs.
Edit: My game is laid out and the sprite panel works exactly as it should, as much as it may sound like it, I am not rushing into anything blindly. I have the game working except for displaying the dialogs in an effective way.
EDIT 2: Ok maybe I am being unclear, my basic concern is finding the best Java component to draw strings to the bottom panels. The strings will be changing regularly, so some methods that I have tried such as the Graphics drawString() are not very effective.
Thank you,
roflha
Well, your original question statement lacks any actual cohesive question, other than "Can anybody start me off or lend me a hand?" which makes it rather hard to figure out what you really need. I discerned that what you want help from us about is displaying dialogues that popup to the user when some event happens. If you don't care too much about special effects, there are three easy ways to do this:
1) Simply have sprites for your messages, and set them to visible as needed. If you have a limited number of important messages, this makes it easy to control the visibility/flashiness of the message.
2) JTextArea allows you to simply print some text to a box. It is useful if you have a wordy console or messages that can't simply be a few images. You would just have a JTextArea in your panel, and update it as needed:
JTextArea messageBox;
messagePanel.add(messageBox);
//displays a message
messageBox.setText("CRITICAL HIT!!!");
But the user may not notice when the text changes, since it changes instantly. Whether you want to flash the text, or display some animation on top of the text area is up to you.
3) If you want a more intrusive message, you can actually have a popup dialogue where the user would have to click "OK" to continue. This is relatively easy to do, and you can even put custom icons for the message:
http://download.oracle.com/javase/tutorial/uiswing/components/dialog.html
JOptionPane.showMessageDialog(myFrame,
"You got a critical hit!!!",
"Critical Hit",
JOptionPane.INFORMATION_MESSAGE,
criticalHitIcon);