I have a hybrid swing application which can be run as applet or java application with the following structure:
public class Gui extends JApplet {
public void init() {...}
public void paint(Graphics g) {
...
g.drawImage(image, 0, 0, this);
}
public static void main(String args[]) {
JFrame frame = new JFrame();
JDialog dialog = new JDialog(frame);
Gui gui = new Gui();
gui.init();
gui.start();
dialog.add("Center", gui);
...
}
}
The whole gui consists of one drawing area which is continously updated.
I would like to embed a panel which is always on top and independent of the underlying drawing process.
I tried using JLayeredPane and add it between JDialog and JApplet, but Japplet cant be added to the Pane because it is a top level container.
I also tried realising it with the glasspane but no success at all.
Is there a solution without refactoring to much since the structure should be kept as far as possible.
Don't override paint() of a top level container, like JApplet or JFrame. Custom painting is done by overriding the paintComponent() method of a JPanel (or JComponent). Then you add the panel to the frame.
dialog.add("Center", gui);
The is not the way to add a component to a panel. Read the Container API to find the proper add(...) method to use. Also don't hardcode string values. Every layout manager contains variables that can be used as the constraint values.
I would like to embed a panel which is always on top and independent of the underlying drawing process.
Not sure this makes sense. If the panel is always on top, then it would cover the painting.
I tried using JLayeredPane
That sounds like the proper approach. You add the layered pane to the frame or applet. Then you can have a background painting panel and another transparent panel on top. Read the Swing tutorial on Using Layered Panes for a working example.
Related
So I'm having a class called Menu which extends JLabel and has a constructor which adds 3 JButtons to itself.
public Menu() {
this.add(jbutton1);
this.add(jbutton2);
this.add(jbutton3);
}
I have another class called GUI which extends JFrame and adds the JLabel to its contentPane.
public GUI() {
Menu menu = new Menu();
getContentPane().add(menu);
setSize(300,200);
setVisible(true);
}
The main method of GUI just looks like this:
public static void main(String[] args) {
GUI gui = new GUI();
}
So what I wanted is a JFrame with 3 JButtons in it (going to do more stuff later one). Instead I just got a blank JFrame. Why don't I see the JLabel with the 3 JButtons in it I added?
You're forgetting layout managers which are key to controlling how components are added to and sized by containers. JLabels are not used to being used as a container and holding other components and so come by default with a null layout -- no layout at all, making you the programmer responsible for sizing and positioning any added component.
Solutions:
Set your JButton's sizes and positions yourself -- a very bad solution since it leads to GUI's that only work well on one platform and that are difficult to debug and maintain
Or give the container (here the JLabel) a decent layout manager.
Or use another container, such as a JPanel, one that already has a layout manager, as the contentPanel. There are ways of getting a JPanel to display an image including overriding its paintComponent method.
You can find the layout manager tutorial here: Layout Manager Tutorial, and you can find links to the Swing tutorials and to other Swing resources here: Swing Info.
I'm doing a program that is composed by multiple panels in a JFrame.
I need to do every elements in differents classes (It's because in my school, we need to have every elements separeated in different classes for clean code), but every example that I see with my kind of problem, they do everything in one class.
And I think that my problem comes from having multile classes so I show you my classes.
I have a panel in wich I need to put 2 panel, here is the code :
public class Inscription extends JPanel{
private PanneauBoutons panneauBoutons = new PanneauBoutons();
private PanneauFormulaire panneauFormulaire = new PanneauFormulaire();
public Inscription(){
this.setLayout(new BorderLayout());
this.setBorder(BorderFactory.createLineBorder(Color.RED, 2));
this.add(panneauFormulaire,BorderLayout.CENTER);
this.add(panneauBoutons,BorderLayout.SOUTH);
this.setVisible(true);
}
}
And here is the Panel panneauFormulaire :
public class PanneauFormulaire extends JPanel{
private JLabel labelMatricule;
private JTextField zoneTexteMatricule;
public PanneauFormulaire(){
this.setLayout(new GridLayout(8,2,10,10));
this.setBorder(BorderFactory.createLineBorder(Color.black));
labelMatricule = new JLabel("Matricule : ");
this.add(labelMatricule);
zoneTexteMatricule = new JTextField(30);
this.add(zoneTexteMatricule);
this.setVisible(true);
}
So the problem Inscription don't appear on the main Frame if I don't do setBounds, but I want a BorderLayout...
(I tested and with a set bounds I can see the borders, so I think that it means the panel are really added to the Frame so why without setBounds I see anything?).
And the other problem is that the panel PanneauFormulaire don't appear on the Inscription panel...
So if I miss something, can you help me? thank you
And here it is the class that extends JFrame :
public class FenetrePrincipale extends JFrame {
private Container cont;
private Inscription inscriptionForm;
public FenetrePrincipale(){
super("IESN");
setBounds(100,100,1200,960);
getContentPane().setLayout(null);
setLocationRelativeTo(null);
setResizable(false);
...
inscription.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
cont.removeAll();
inscriptionForm = new Inscription();
inscriptionForm.setOpaque(true);
cont.add(inscriptionForm);
invalidate();
repaint();
}
});
You should NOT be using a null layout and setBounds(). Swing was designed to be used with layout managers.
but when I click on an option in the menu, the current panel need to be change by another one,
Then you should be using a CardLayout.
Read the section from the Swing tutorial on How to Use CardLayout for working examples. So download the example and use it as the starting point of your project. The code will be better structured then what you currently have and it is easier to change working code than it is to fix broken code.
so why without setBounds I see anything?
That is because you set your layout to null in getContentPane().setLayout(null);.
Java containers comes with a default layout which you are allowed to set to a different one. How the components are arranged in the container are dependent on the layout you use. The layout will directly affects the location, alignment, spacing, dimension, preferredSize of the components.
However, if you choose not to use any layout (.setLayout(null)). Swing will not know how you want the components to be arranged, hence you see nothing in your content pane.
Since you wanted "absolute control" over the components, you will be expected to set the bounds (location and dimension) of each added component manually by yourself. This is why you are not seeing any components (even if you already added it) until you set the bounds for them.
Java, elements don't appear in a Panel with a GridLayout or FlowLayout, but with a setBounds they do
Every layout has their own characteristics and for some of them the order of your codes does makes a difference. Hence, I will advise you to go through what each layout can do for you. Then, depending on your needs, choose one (or a combination of a few) and study how to use it.
And here it is the class that extends JFrame :
You probably won't want to extends to a JFrame. You can always make a customized Container like JPanel and add it to the frame.
(Why would you want to paint your paintings on a frame instead of a piece of paper?)
I need to have a JFrame where the upper part is a drawing made by paint() and the lower part is a panel composed of JLabel, JTextField and JButton components.
Is this possible? How am I supposed to do this?
I need to have a Jframe where the upper part is a drawing made by paint() and the lower part is a panel composed of JLabel, JTextField and JButtons.
There is no conflict on what you want to do. You can have a main JPanel with 2 sub panels. One on the top for your drawings, the other at the bottom for containing your JComponents such as JButtons:
The structure in code may look like this:
class MainPanel extends JPanel{
private DrawingSpace drawingSpace; //Customized JPanel for drawing
private JPanel subPanel;
public MainPanel(){
setPreferredSize(new Dimension(400, 400));
initComponents();
}
private void initComponents(){
drawingSpace = new DrawingSpace();
subPanel = new JPanel();
}
}
You can have a customized JPanel as follows (this is optional):
class DrawingSpace extends JPanel
{
public DrawingSpace(){
//Set size..etc
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
//perform your drawings here..
}
}
After the implementations for the JPanels, you can just add an instance of MainPanel to the JFrame:
JFrame frame = new JFrame();
frame.add(new MainPanel());
//Other codes for JFrame not shown here
The soulution suggested by user3437460 (use a JPanel for the upper part, and override the painting methods in that JPanel) is the preferrable way to solve this.
However as you asked for a solution to directly paint the upper part (which is not advised, but there are solutions):
A (nasty) workaround for the question would be overriding the necessary paint method of JFrame, draw your upper part, translate the graphics context by some 100 pixels and call inherited paint methods to draw the bottom part. (Note that you'll have layout manager issues, as the layout manager won't see the 100px height of the upper part. However, if you're using an absolute layout, it could work. Hacks, hacks hacks :(
Another super-hack is to actually make the lower part big enough (if you use absolute layout, position your lower part at y=100px). Then add your own GlassPane and render the content for the upper part (or anywhere) on the glassPane.
Of course you can create a dedicated layout manager, which leaves the top 100 px part empty. Use that layout manager, and then you get some empty space on the top, which you can draw on.
I think now you can agree that the problem is rather "how to put a custom drawn component on the top of the window", which is solved by putting a custom drawn JPanel on the top of the window. Keep it easy! Peace!
ps: override paintComponent() instead of paint() of JPanel. See bottom of http://www.oracle.com/technetwork/java/painting-140037.html
For the painting portion, create a JPanel (or other paintable component) and override the paint method. Use a second JPanel and place all of your other components in that.
From there, check out how to do layout management at https://docs.oracle.com/javase/tutorial/uiswing/layout/using.html#set
The simplest way to do this is to use GridLayout, with the painted panel on the top half and the components panel on the bottom half.
I have an LWJGL OpenGL Display showing up inside an AWT Canvas, which in turn is inside a Swing JPanel that is used as content pane for a Swing JFrame. At some point in the program, I want to switch the AWT Canvas containing the Display for a JComponent, so that instead of having something like that:
JFrame > JPanel > Canvas > Display
I have something like so:
JFrame > JPanel > JComponent
However, even though I remove the Canvas from the JPanel and add the JComponent, then revalidate the JPanel and repaint it, the Display still shows until I CTRL-ALT-SUPPR to task manager (my JFrame is set Undecorated and ExtendedState is JFrame.EXTENDED_BOTH, so it is full screen). At which point, the JComponent shows up like nothing ever happened..
I'll share the part of my code that does the transition so you can maybe help me point out what I have done wrong:
public static void switchTo(Container container){
pan.removeAll();
container.setBounds(0, 0, Toolkit.getDefaultToolkit().getScreenSize().width, Toolkit.getDefaultToolkit().getScreenSize().height);
pan.add(container);
frame.getContentPane().validate();
pan.revalidate();
pan.repaint();
}
where pan is my JPanel and frame is my JFrame.
I have also tried directly setting my JComponent as my JFrame's content pane, but that gives the exact same result.
The only way I managed to make it function correctly was by calling destroy() on the Display beforehand; however, I need to keep the OpenGL context running so that I don't have to re-initialize the Display and reload every texture when switching back to the Display, which would be quite a long process given the number of textures I have.
Thank you very much for any answer, I hope I made myself clear!
Is it possible to draw on a JFrame without adding a JPanel to it?
i override paintComponents() but it didn't show anything.
#Override
public void paintComponents(Graphics g) {
super.paintComponents(g);
g.drawString("for test", 10, 10);
}
Just in case anybody still insists of painting on the top-level Window directly (which is not recommended), here's how (because the code snippet linked to in the other answer is simply wrong)
JFrame frame = new JFrame("funny ...") {
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawString("for test", 150, 150);
}
};
frame.getRootPane().setOpaque(false);
((JComponent) frame.getContentPane()).setOpaque(false);
Obviously, to make it shine-through all the way up, everything above (in Z-order) has to be not-opaque.
Cheers
Jeanette
Yes, it is. You'll want to work with the one of the panes in the JFrame such as the content pane or the glass pane, which you can access via getContentPane, etc.
For example the content pane is a Container, with a variety of add methods. To that you can add any Component - doesn't have to be a JPanel specifically. More at Using Top Level Containers.
Usually, though, drawing is done via overriding paint (for AWT) or paintComponent (for Swing). This means you need some sort of Component or JComponent that you put in your frame. More at the 2D Graphics tutorial. Why do you not want to change that?
You can also override JFrame and its content pane and have a content pane with an override paintComponent method.
I question, however, the necessity and wisdom of directly drawing on a JFrame.
It seems to be possible. Check this previous SO post to see how it can be done.
JFrames have a GlassPane on top of them, which can be used for graphics. Here you have a simple example that shows how to use it.