JScrollPane and printAll() - java

I am working on a JPanel extension that is only for rendering its contents to a BufferedImage, which I then use as a texture for rendering in OpenGL. For this, I create my special JPanel extension with a layout manager etc., like I would if I was building a normal Swing GUI.
In order to render it to an image, I make sure to call doLayout first and then I use the printAll(java.awt.Graphics) method to print it and the added components:
Graphics2D g = image.createGraphics();
printAll(g);
Swing itself (EDT, RepaintManager etc) is never involved, I just create the components (outside any window or frame) and directly use printAll.
This is working perfectly well for most "atomic" components (such as buttons, labels, lists), but I hit on a problem with the JScrollPane. Whatever I try, the JScrollPane will never paint its viewports (the main viewport and the scroll bars) to the given Graphics but only its border, and even manually calling printAll on the viewports yields no result.
I attached two screenshots which show a "before and after" of a simple GUI consisting of a JList and a JButton. On the first image, I use the raw JList, in the second image, I wrapped it into a JScrollPane using new JScrollPane(list).
I failed to find any magic inside the JScrollPane code related to painting its viewports. Maybe something needs to be initialized that Swing would do, but I forgot. Is there any way I can get those viewports to show up?

See Why does the JTable header not appear in the image? for some general tips about rendering components to images. Try calling combinations of validate(), addNotify() & doLayout() as mentioned in the code of that thread.

not sure from your question
1) if there is about JScrollPane or JViewport, becasue JViewport is only (from JScrollPane) about visible Rectangle on the screen,
2) every JComponent returns Graphics2D
3) please why do you call doLayout() / addNotify(), in the case that all events for Swing GUI are done on EDT, or are there some events based on Swing Timer
4) better would be edit your question with SSCCE that generated un_wanted output to the GUI
5) for JViewport you have to create and override your own RepaintManager
6) maybe stupid question, please ensure us that there isn't any animations of JComponent, meaning moving accross JScrollPane and freezed on EDT by Thread.sleep(int)
EDIT (could be most important)
7) for OpenGL you have to implements Components based on Java AWT

Related

Java - Swing - displaying multiple JComponents in one JFrame

in a game, I would like to display simultaneously two JComponent instances in a JFrame. One would be a background board, the another - a player character.
So, one component (a background) would be behind another (a character). The character would be drawn of several rectangles and thus it will most commonly have some wholly transparent area.
How to do that? I know that normally, when I add two components to a frame (method add(Component)), only the last-added component is visible. This is done by following code:
frame.add(backg); // backg is an instance of a certain class that derives from JComponent
// (...)
frame.add(psc); // psc is an instance of an another class that derives from JComponent
frame.pack();
frame.setVisible(true);
How should I change the code above?
First of all, if you are looking to write a game in Java, try out Slick2D provides numerous tools and far better graphical capabilties (being wrapped around LWJGL which wraps around OpenGL). Secondly, if you do decide to go the Swing route, here's a simple solution:
//Player + background components defined here
playerComp.setOpaque(false);
JLayeredPane layer = new JLayeredPane();
layer.add(backgroundComp,1,0);
layer.add(playerComp,2,0);
I believe that both these solutions were mentioned above in the comments. Setting the player component opaquity to false allows those transparent areas to show components behind the player, or the background image. If you're familiar with a z-index in CSS/HTML, a JLayeredPane basically adds a z-index to Swing by allowing you to set the order in which components are rendered. So, set the player to opaque, and then render it in front of the background component.

Java Swing: how to shade a game gui after the match has finished

In a board game we are developping in Java we would like the gui to be overshadowed when the game is finished. We have a Jframe in which there is JPanel with the board on which there are some colored pawns and boxes (JButtons) and we would like that everything becomes a sort of black and white and grey. Is there an authomatic method in Java to do this in Java Components?
There are several different kinds of panes to look at that could achieve this, or something similar, if you are using Swing (which I assume from the tag, that you are).
You could use a Glass Pane. http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html#glasspane
glass panes could be thought of as like a CSS overlay. They dis-allow interaction with components behind them.
Also, take a look at JXLayers and JLayers, they allow you to modify the way components are actually painted.
Good Luck!
Override paintComponent() (Or if you have some components added to the container it's better to override paintComponents() method).
Call
super.paintComponent(g);
Color semiColor=new Color(0,0,0,128);//the last param represents alpha
g.fillRect(semiColor);

Using swing components with an applets paint method

I have a functioning Java applet which can be embedded into a web page and wish to now add some swing components for additional functions. However whenever I add a component like a JLabel, it simply does not appear on the viewport/canvas unless I remove my entire paint method. The latter option allows me to add swing components but naturally I then cannot render any shapes. It appears to resemble an eXclusive OR (XOR), either one but not the other.
Is there anyway in a native Java applet to add swing components and still maintain the paint(Graphics g) method. Please note that I am inheriting from Applet and not JApplet.
If you override paint method in applet then there is no simple way.
What you could do instead of overriding paint in applet.
Extend JComponent instead and do the custom drawing there.
create JPanel that contains all the needed swing components including the component from earlier step.
Add that panel to applet which is using default paint method.
I suggest that you add the components to a separate panel that doesn't override paint. By overridding paint, you are customizing the way the component is drawn, so the layout manager and the components it has to manage do not count, it's only the implementation of paint you wrote that dictates how stuff is rendered.
So, your applet would contain a panel with the components and a panel that does the custom painting.
At the end of your paint method, call super.paint(g).
I was able to visualise the components over the applet canvas by invoking
paintComponents(g);
Thus the components are thereafter painted AFTER the actual paint(Graphics g) method completes its epoch.

How to successfully modify the way a JFrame (and all of its components) paint?

I'm trying to implement a simple window scale in java's swing library. The goal is simply to double the window height and width, and paint the window and each of its components in scale.
Here's an example of the code I'm using:
public class MyWindow extends JFrame {
...
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.scale(2,2);
super.paint(g);
}
}
The position and size for each my components in this window is set manually using setBounds with a null layout for the window.
When I actually run the program, what happens is that the first paint for the window seems successful-- everything is sized appropriately. Each subsequent repaint by the components, however, is neither twice the size, nor in the proper location. Here's what I mean:
As you can see, portions of the screen which have components that call repaint manually (the animating bits), don't seem to be using the Graphics2D scale of the JFrame. I looked in the source code, and tried overloading a few other methods (update and repaint, mostly), but all of them seemed to produce the same result. I further looked at the paint and repaint methods of the component and container classes, but they all seem to call a specified repaint of their parent. Shouldn't my Window be the "biggest" parent? If so, why haven't these repaint calls reached my Window?
My big question to you is, therefore: what repaint methods of the parent component do the child components call? Why aren't the calls properly routed to my JFrame's paint call? Is there any other (better) way that I can scale my window? Any and all help is appreciated!
As discussed in Painting in AWT and Swing: The Paint Methods, "Swing programs should override paintComponent() instead of overriding paint()." A common approach is to create a view by overriding paintComponent() in a JComponent (or subclass), as shown here. Let your view listen for changes to the game's model, as discussed here.
SwingUtilities.updateComponentTreeUI() should be used to change the Look & Feel, not update the view.
Use
javax.swing.SwingUtilities.updateComponentTreeUI(parentComponent);
when you need to make sure all of the parentComponents child component's look and feel are updated properly.

How to make a Java Canvas look raised from its container

I have a simple GUI component written in Java. The class draws an analog clock in a java.awt.canvas.
This canvas is then contained in a JFrame - What I want to do is give the canvas a 3d "raised" effect - almost like adding a drop shadow to a photo.
Is there a simple way to do this?
If you are using a JFrame, then you have two options:
Add your own component to a JPanel first and then add this to the JFrame.
Instead of inheriting from java.awt.Canvas, you can inherit from JComponent. Then you would have to do all your painting in the paintComponent() Method instead of just paint() (you can just rename your current paint method).
In both cases you can now set a border with the setBorder() Method (on the JPanel or your component) you can get from BorderFactory.
See also: How to Use Borders
If you were using a Swing element, you'd use the createRaisedBevelBorder() method of the BorderFactory and set the canvas' border to the resulting border. Canvas is an AWT component, so you'll need to wrap it in a Swing component to which you can set the border.

Categories

Resources