How do I properly paint to a frame/panel? - java

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

Related

Can't stop flickering on JPanel

I have class that creates a new thread.
`
public ScreenG(JPanel PanelR)
{
Panel = PanelR;
RenderImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
FPS = 25;
Hide = false;
(new Thread()
{
public void run()
{
while(true)
{
if(Hide == false)
{
Timer = System.currentTimeMillis() + (1000/FPS);
if(!DrawRendering)
{
Graphics g = Panel.getGraphics();
g.drawImage(RenderImage, 0, 0, null);
}
DrawRendering = false;
while(System.currentTimeMillis() <= Timer) try { Thread.sleep(1); } catch (InterruptedException e) {Thread.currentThread().interrupt();}
}
}
}
}).start();
}
public void draw(BufferedImage ImageR)
{
DrawRendering = true;
RenderImage = ImageR;
Graphics g = Panel.getGraphics();
g.drawImage(RenderImage, 0, 0, null);
}`
In my main I create a new instance of ScreenG. This will start a new thread that draws a bufferedImage onto a JPanel with a consistent FPS.
In the main I would then call draw with the image that I created. Sometimes it works but sometimes the image on the panel flickers. I try variations like the draw function taking over the drawing. Non of them work. I could only REDUCE the flickering.
Not possible by design. Swing does not synchronize to the bitmap raster DMA that's actually sending the screen data to your monitor, so it always possible that the screen buffer is read by the DMA while you're busy rendering to it (possible exception is Fullscreen mode).
To at least minimize flickering follow the recommended method of custom Swing painting: https://docs.oracle.com/javase/tutorial/uiswing/painting/
You can easily trigger periodic repaints on the EDT using a Swing timer, or SwingUtilities.invokeAndWait/invokeLater from another thread (whatever works best in your design).
The flickering can be because the rendering isn't fast enough from an update.
Now I do recommend you use Swings paintComponent (Graphics g) when rendering its components. That being said. To solve the flickering for you add a BufferStrategy in your JFrame
Without that code avaible I can only provide a general solution.
JFrame jframe = new JFrame ();
...
BufferStrategy bufferstrategy = jframe.getBufferStrategy ();
if (bufferstrategy == null) {
jframe.createBufferStrategy(3);
return;
}
g.dispose();
bufferstrategy.show();
To read more about BufferStrategy I recommend a read over at the documentation.
Small Note
There is no reason in your code to either store JPanel PanelR or BufferedImage ImageR. You can instead directly invoke methods directly on PanelR resp. ImageR.
Thank you for the answers. I read Oracle tutorial that you recommended and get my paintComponent() function working correctly on the main thread. To do that I am calling JPanel().repaint() from the draw() function. I will learn about using BufferStrategy next.

Processing 2 - Will threading speed up rendering many objects?

I'm working on a processing sketch here: https://github.com/davidcool/processing/tree/master/polyhedrons/polyhedrons_4
It's not very elegant code-wise but works fine. It renders rotating complex (meaning many faces) polyhedrons to the screen. Each time you click it adds 5 new rotating polyhedron objects... Once you have 20-25 objects it starts to bog down, meaning the frames/sec drop and it looks jumpy.
I've been reading about threading in Processing/Java. So I started to think maybe I could split the total number of objects out to each processing core. I saw this example in particular: http://www.camnewnham.com/threading-in-processing/
Before I dive into this goose chase, does anyone know if threading would help in terms of animation speed? When I run a sketch normally does it always just use one core for the draw loop? Can threading spread out the object animation rendering over "idle" cores?
Thanks!
The draw() function is always called by the same Thread. This same Thread also calls the mousePressed() and similar functions. In Processing this is called the Animation Thread- Java has a similar idea, called the EDT.
So you can't simply move your drawing to other threads. This will cause problems with the rendering- for example, the Animation Thread might be trying to draw the next frame, while your drawing threads are still trying to draw the previous frame. It's not going to work.
You could try to do your own multi-threaded off-screen buffering by having all your helper threads draw to a PGraphics instead of calling the Processing drawing methods directly. You'd then have to synchronize all of your drawing threads and only draw your PGraphics to the screen (using the Animation Thread) after all of those threads have finished.
This is not a particularly difficult job, but it does involve a pretty decent understanding of how threading works, which goes beyond the scope of most Processing sketches.
Also note that JavaScript doesn't have multiple threads, so anything you do with threading will not work in JavaScript mode.
Here's an example sketch that uses just the Animation Thread to draw 10000 random points every frame. I get about 7 FPS with it:
PGraphics sharedGraphics;
void setup(){
size(500, 500);
sharedGraphics = createGraphics(500, 500);
}
void draw(){
sharedGraphics.beginDraw();
sharedGraphics.background(0);
for(int i = 0; i < 10000; i++){
sharedGraphics.ellipse(random(500), random(500), 5, 5);
}
sharedGraphics.endDraw();
image(sharedGraphics, 0, 0);
println(frameRate);
}
And here is how you might use multiple Threads to render to a PGraphics:
PGraphics sharedGraphics;
void setup() {
size(500, 500);
sharedGraphics = createGraphics(500, 500);
}
void draw() {
ArrayList<Thread> threads = new ArrayList<Thread>();
sharedGraphics.beginDraw();
sharedGraphics.background(0);
for (int i = 0; i < 100; i++) {
Thread t = new DrawThread();
threads.add(t);
t.start();
}
for (Thread t : threads) {
try {
t.join();
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
sharedGraphics.endDraw();
image(sharedGraphics, 0, 0);
println(frameRate);
}
class DrawThread extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
sharedGraphics.ellipse(random(500), random(500), 5, 5);
}
}
}
However, the performance of that is even worse than the single-threaded model, and I get strange artifacts (some of the ellipses are filled, others are not) which suggests that PGraphics is not thread-safe. That might depend on the type of renderer you're using. You might then add some synchronization:
class DrawThread extends Thread {
public void run() {
for (int i = 0; i < 100; i++) {
synchronized(sharedGraphics) {
sharedGraphics.ellipse(random(500), random(500), 5, 5);
}
}
}
}
That works, but the performance of it is even worse, since you're still only accessing the PGraphics with one thread at a time, and you're doing a bunch of extra work every time draw() is called.
You might be able to fiddle around with it to make it work, but the end result is that it's probably not worth it.
"Some people, when confronted with a problem, think “I know, I'll use multithreading”. Nothhw tpe yawrve o oblems."

Updating Swing components while blocking the GUI

I was programming a GUI today, which is doing longer calculations when pressing a button. While the calculations are running, I wanted to use intermediate results of the still running calculation and write them to a JLabel. The GUI however, should not be operable by the user before the calculation has finished.
At first I was doing something like this:
(1)
public class GUI extends JFrame {
JLabel label = new JLabel("Status: ");
public GUI(){...}
public void calculate() {
for(int i = 0; i < 10; i++) {
String one = calculationPartOne(i);
label.setText("Status: " + one);
label.repaint(); //*
calculationPartTwo(i);
}
}
}
This did not work, the JLabel would only update after the calculation has finished. I also tried to .repaint() and .validate() all components involved at the line commented *, but it did nothing.
So, after trying and searching Google/StackoOverflow the whole day I finally have a working solution, but I still do not understand why above does not work. I wanted the GUI to block, so naturally I ran the calculation in the same thread. However, calling any methods to repaint the GUI -inbetween- the calculation (making the calculation stop while the GUI is updated) did not work, and I do not understand why. Can someone explain?
In the end, I used the SwingWorker class to do my calculations, and use it's functions to update the JLabel while calculating. However, as I need the GUI to block, I now disable -all- the components before excuting the SwingWorker and have the SwingWorker re-enable all the components after finishing the calculation.
So, I use SwingWorker, to not block the EDT, but then "fake" to block the EDT by disabling everything? This seems really paradox to me.
Here is an outline of what I have now:
public class GUI extends JFrame {
JLabel label = new JLabel("Status: ");
//I didn't use a list, but it works to illustrate it here
List<Component> GUIComponents = ...;
public GUI() {...}
public void calculate() {
SwingWorker<Void, String> worker = new SwingWorker<Void, String>() {
protected Void doInBackground() throws Exception {
for(int i = 0; i < 10; i++) {
String one = calculationPartOne(i);
publish(one);
calculationPartTwo(i); //**
}
}
protected void done() {
setEnableGUI(true);
}
protected void process(List<String> chunk) {
label.setText(chunk.get(chunk.size() - 1));
}
};
setEnableGUI(false);
worker.execute();
}
public void setEnableGUI(boolean e) {
for(Component c : GUIComponents) {
c.setEnabled(e);
}
}
//**
public void calculationPartTwo() {...}
}
This works.
I hope someone can clarify. This solutions feels wrong.
why wrong? the gui thread is for responding to user events only - so you should be doing your heavy lifting in the background - which is what youre doing with a SwingWorker.
also, the best way to prevent a user from changing a componenet is to do exactly that - disable the component before starting the heavu lifting, and enable once its done.
only thing you might want to consider is displaying the results of your calculation in a modal dialog - a JDialog that will pop above the parent window and block it. you could display the intermediate results and progress in this dialog and then once the calculation is done the dialog will close and unblock the UI obscured by it. this will save you fron having to disable all gui components indiviually in a loop and will also give you an option to have a "cancel" button to halt the work immediately.
However, calling any methods to repaint the GUI -inbetween- the calculation (making the calculation stop while the GUI is updated) did not work, and I do not understand why. Can someone explain?
repaint() requests are handled by the RepaintManager and are not done immediately. The RepaintManager basically schedules the repaint. Since repainting is done on the EDT, it can't be done until the EDT is free.
So, I use SwingWorker, to not block the EDT, but then "fake" to block the EDT by disabling everything? This seems really paradox to me.
You can always use an indeterminated JProgressBar. See How to Use Progress Bars.
Or maybe you would prefer to use the Disabled Glass Pane approach.
In some cases you can use:
label.paintImmediately(...);
to force the repainting of a component. But you still have the issue of disabling the GUI so its probably not a solution you should really be using.

How to immediately change text of jLabel inside MouseEvent handler?

I have problem with refreshing swing components inside Mouse action event handler. Problem is that all jLabels which are changed in this function that their changes are visible after jButton1MouseClicked() is done. Here is my function:
private void jButton1MouseClicked(java.awt.event.MouseEvent evt) {
int cycles = Integer.parseInt(c.settings.get("cycles"));
statusMessageLabel.setText("Data collection in progress...");
for(int i=1;i <= Integer.parseInt(c.settings.get("cycles"));i++) {
jLabelCycle.setText(Integer.toString(i));
//here are some functions which are implementing data collection
if(i < cycles){
int counter = Integer.parseInt(c.settings.get("interval"));
while(counter >= 0){
jLabelTimer.setText(Integer.toString(counter));
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(AppCView.class.getName()).log(Level.SEVERE, null, ex);
}
counter--;
}
}
}
statusMessageLabel.setText("Data collection has been finished.");
}
Can you please help me ? I really need this changes to be visible immidiaetly because one jLabel visualize counting till next cycle and second one is visualizating actual cycle number. I tried call function repaint() on all jLabels after i changed them but it didnt help.
Thank you all for any help.
In AWT, much like most other GUI systems, all events including repaints are done on a single thread, the AWT Event Dispatch Thread (EDT). You are blocking that thread in the event listener, so the repaint events on the label cannot get through.
I suggest rewriting your code to use use javax.swing.Timer instead of Thread.sleep.
In general, long running operations should be handled on a separate thread. Any operations touching AWT or Swing components should be queued for running on the AWT EDT using java.awt.EventQueue.invokeLater.

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