How to add a GUI panel and a DrawPanel within one frame? - java

I want two Panels to be added here within one frame, I want some buttons and text fields on the right side there to edit the drawing panel class but I can't figure out how to add GUI components to panel2. Whenever I try to add GUI components to panel2, it just doesn't work how it would work normally and I don't understand why.
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setTitle("WaferMap");
frame.setSize(1286, 829);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
Container contentPane = frame.getContentPane();
contentPane.setLayout(new BorderLayout());
DrawingPanel panel1 = new DrawingPanel();
JPanel panel2 = new JPanel();
frame.add(panel1, BorderLayout.WEST);
panel1.setPreferredSize(new Dimension(1080, 800));
final JButton button = new JButton();
panel2.add(button, BorderLayout.EAST);
button.setBounds(50,50,100,50);
frame.add(panel2, BorderLayout.EAST);
panel2.setPreferredSize(new Dimension(200, 800));
}
}
This is the main, I have another class called drawingPanel with a paintComponent in it.

Don't use setPreferredSize(). It is the job of the layout manager to calculate the preferred size of the panel based on the rules of the layout manager and the preferred size of the components added to the panel.
Don't use setSize(). Instead use pack(). The frame will be sized based on the preferred size of all components added to the frame.
The real problem is that by default a component has a size of (0. 0) so there is nothing to paint. It is the job of the layout manager to give the component a size/location to the component. The problem is that you made the frame visible before you added the components to the panel, so the layout manager was never invoked. So the solution is that the pack() and setVisible(true) statements should be invoked AFTER all components have been added to the frame.
Note, the tutorial also has a section on Custom Painting that you should be reading so you implement the painting properly to make sure your DrawingPanel has a preferred size.

Related

Java cannot display the JPanel, but can display JLabel?

The question is that I cannot add JPanel and JLabel in the Frame at the same time.
When i using following code, only MyPanel will be visible. myFrame.add(myLabel);myFrame.add(myPanel);myFrame.setVisible(true);
when I execute: myFrame.add(myLabel);myFrame.setVisible(true);myFrame.add(myPanel);
only myLabel will be visible.
import javax.swing.*;
import java.awt.*;
public class Main {
public static void main(String[] args) {
MyFrame myFrame = new MyFrame();
MyLabel myLabel = new MyLabel();
MyPanel myPanel = new MyPanel();
myFrame.add(myLabel);
myFrame.add(myPanel);
myFrame.setVisible(true);
}
}
public class MyFrame extends JFrame {
MyFrame() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //exit out of application.
//https://docs.oracle.com/javase/7/docs/api/javax/swing/JFrame.html#setDefaultCloseOperation%28int%29
this.setSize(750, 750); //set the size.
this.setResizable(true);//resize the frame.
this.setTitle("Welocme to new world."); //set the Title.
ImageIcon imageIcon = new ImageIcon("logo.png");
this.setIconImage(imageIcon.getImage());
this.getContentPane().setBackground(new Color(217, 217, 217));
this.setBackground(Color.YELLOW);//this.setVisible(true);//Make the frame visible.
}}
import javax.swing.*;
import java.awt.*;
public class MyPanel extends JPanel {
MyPanel() {
this.setBackground(Color.white);
this.setBounds(2,2,25,25);
}}
import javax.swing.*;
import java.awt.*;
public class MyLabel extends JLabel {
MyLabel(){
this.setText("<html>Heaven <br/>Heaven's body\"<br/> Whirl around me <br/>Make me wonder</html>");
//,SwingConstants.CENTER);
//https://stackoverflow.com/questions/1090098/newline-in-jlabel
//How to print multi line in java
ImageIcon image = new ImageIcon("Cosmogony_Björk_Cover.jpg");
this.setIcon(image);
//jLabel.setForeground(new Color(217,217,217));
this.setForeground(Color.BLACK);
this.setFont(new Font("helvetica",Font.PLAIN,18));
this.setBackground(Color.gray);
this.setOpaque(true);
//jLabel.setVerticalTextPosition(JLabel.TOP); Set the relative text position of the label.
//jLabel.setBorder();
this.setVerticalAlignment(JLabel.CENTER);
this.setHorizontalAlignment(JLabel.CENTER);
}}
The default Layout Manager of JFrame is the BorderLayout.
Since you did not change the layout manager of your JFrame this is also the current layout manager used in your snippet.
Usually, when using the BorderLayout, you specify which area of the BorderLayout should be populated when adding a component. This is usually done via
frame.add(component, BorderLayout.CENTER);
Notice the area specification in the add() method, which tells the BorderLayout where to place the component.
Here is the issue however. If you use the add() method in combination with the BorderLayout without specifying the placement of the component, it will always place the component in BorderLayout.CENTER. (Causing the component which is currently there to be replaced)
To work around this, do one of the following things:
Specify the placement explicitly, so both components will show up:
frame.add(component1, BorderLayout.PAGE_START);
frame.add(component2, BorderLayout.CENTER);
Or use a different Layout Manager, which will take care of the placement for you. E.g. FlowLayout
JPanel contentPanel = new JPanel(); // JPanel uses flowlayout by default!
contentPanel.add(component1);
contentPanel.add(component2);
myFrame.setContentPane(contentPanel);
You could also explicitly set the layout:
Container contentPane = myFrame.getContentPane();
// creates new FlowLayout and sets on content pane
contentPane.setLayout(new FlowLayout());
contentPane.add(component1);
contentPane.add(component2);
Sidenotes:
Look through the Laying out components within a container Oracle tutorial, which will give you more information on which layout managers there are and how to work with them.
When building your GUI, setVisible() on the JFrame should be the last thing you are doing after adding all components. Because if you add components after setting the frame visible, the changes will not immediately take effect without you telling swing that something changed.
When correctly working with the Swing Layout Managers, there should be no need to use things like setBounds(...) or setSize(). After adding all components, calling pack() on the JFrame is the preferred way to go. This will size the JFrame according to the preferred size of the components inside.

Nothing happens when setting the background of JScrollPane.getViewPort()

I have a JPanel with layout set to null and the background is white. Then I added that JPanel to JScrollPane.
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class TestJScollPane extends JPanel {
private static final long serialVersionUID = 1L;
public TestJScollPane() {
initUI();
}
private void initUI()
{
JScrollPane scrollPane = new JScrollPane();
scrollPane.getViewport().setBackground(Color.GRAY);
scrollPane.setBounds(1, 1, 200, 200);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
setBorder(BorderFactory.createEtchedBorder(Color.GREEN, Color.MAGENTA));
setBackground(Color.WHITE);
setLayout(null);
JFrame frame = new JFrame();
scrollPane.setViewportView(this);
frame.add(scrollPane);
frame.setLayout(null);
frame.setVisible(true);
frame.setSize(800, 500);
frame.getContentPane().setBackground(Color.BLACK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(30,30);
}
public static void main(String[] args)
{
new TestJScollPane();
}
}
My scenario is I have a zoom tool that if I zoom out the JPanel and all its shapes that were painted were scaled using AffineTransform. So I expect that if I zoom out, the background of JScrollPane was color gray but the actual was color white.
Apologies, I added a sample. Actually, this is not the actual code I created this so that I can provide a sample for you guys to help me.
I set the preferred size of JPanel to 30x30 so I expect that the background of JScrollPane will become visible but it was not.
Thanks in advance for any help.
By default the panel is sized to fit the viewport so you will not see the background of the viewport.
You need to implement the Scrollable interface of your JPanel to tell the scroll pane you want the panel displayed at its preferred size.
Or, instead of implementing the Scrollable interface yourself you can use the Scrollable Panel which, by default, will display the panel at its preferred size.
Changes to your code would be:
ScrollablePanel panel = new ScrollablePanel();
panel.setPreferredSize( new Dimension(30, 30) );
panel.setBorder(BorderFactory.createEtchedBorder(Color.GREEN, Color.MAGENTA));
panel.setBackground(Color.WHITE);
//panel.setLayout(null);
scrollPane.setViewportView(panel);
//scrollPane.setViewportView(this);
Change:
scrollPane.setViewportView(this);
To something like:
JPanel centerPanel = new JPanel(new GridBagLayout());
centerPanel.add(this);
scrollPane.setViewportView(centerPanel);
A GridBagLayout (by default, unless configured otherwise) will respect the preferred size of the child components and won't stretch them to fill the 'cell'. A scroll pane on the other hand, will stretch the content to (at least) fill the visible area.
Result:
But seriously, drop the use of null layouts. If the effect cannot be achieved using an existing layout (inbuilt or 3rd party) or a combination of layouts, it must have such esoteric positioning constraints that it deserves a custom layout manager.

How can I display 2 different panels at the same time?

My first panel's layout is BorderLayout and my second panel's layout is GridBagLayout. I don't know how to show them both at the same time.
I already tried adding two panels to on another panel.
Adding both to another panel is the way to go! But you have to make the right choice of LayoutManager for this "parent" panel. Let me give you an example:
The JFrame's content pane (where you add all your Components to) can be setup with a LayoutManager of your choice. See this runnable example, which creates two JPanels of 100x100 pixels in different colors. The panels are using the LayoutManagers you mentioned, but the main content pane of the JFrame is set to a BoxLayout (horizontal, but you can also set it to vertical!).
You can do this to any other panel, too. A panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); is enough. The below example just uses the content pane, but you can adapt it to your needs:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TwoPanels extends JFrame {
private static final long serialVersionUID = 1L;
private static final Dimension DEFAULT_DIMENSION = new Dimension(100, 100);
public static void main(String[] args) {
new TwoPanels();
}
public TwoPanels() {
//create panel 1
JPanel panel1 = new JPanel(new BorderLayout());
panel1.setPreferredSize(DEFAULT_DIMENSION);
panel1.setBackground(Color.RED);
//create panel 2
JPanel panel2 = new JPanel(new GridBagLayout());
panel2.setPreferredSize(DEFAULT_DIMENSION);
panel2.setBackground(Color.GREEN);
//set content pane layout
setLayout(new BoxLayout(this.getContentPane(), BoxLayout.X_AXIS));
//add to content pane
add(panel1);
add(panel2);
//setup and display window
pack();
setVisible(true);
}
}
It looks like this:
EDIT: It's a little unclear from your question that you actually want to stack overlaying panels. You might find what you need here: https://docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html

How do I resize a button?

How do you resize the button? I've tried various methods like setSize and setPreferredSize but they aren't workng.
package tests;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;
public class RPS extends JPanel{
public static void main(String[] args) {
JFrame frame = new JFrame("Rock Paper Scissors");
JPanel panel = new JPanel();
JLabel label = new JLabel("<html>Will you choose <i>rock,</i> <i>paper,</i> or <i>scissors?</i></html>");
JButton button = new JButton("I am a button.");
label.setHorizontalAlignment(0);
label.setVerticalAlignment(1);
frame.pack();
frame.getContentPane();
frame.setTitle("Rock Paper Scissors");
frame.setSize(640, 480);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.add(label);
frame.add(button);
button.setToolTipText("Y U no click me?");;
}
}
There is generally no need to resize a button. The button will determine its own size based on the text and Font used by the button. The layout manager will then use this information to give the components a size and location based on the rules of the layout manager.
If you want extra space around the text then you can use:
button.setMargin(...);
You have many other problems with your code:
frame.add(panel);
frame.add(label);
frame.add(button);
This won't do anything. By default the content pane of the frame uses a BorderLayout. If you don't specify a constraint, then then component is add to the CENTER, but only one component can be displayed in the CENTER so you only see the last one.
frame.setSize(640, 480);
There is no need for that statement. The pack() will set all the components at their preferred sizes.
frame.setVisible(true);
This should be the last statement executed, "after" all components have been added to the frame.
frame.getContentPane();
This does nothing, you don't assign the returned value to any variable.
label.setHorizontalAlignment(0);
label.setVerticalAlignment(1);
Don't use magic numbers. Nobody knows what 0 and 1 are used for. Read the API for those methods for variables that you can use.
Read the section from the Swing tutorial on Layout Managers for more information and working examples to get you started. Start with the section on How to Use BorderLayout to understand why your current code isn't working and to understand how to specify the "constraints" when you add your components to the frame.
package tests;
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class RPS extends JPanel{
public static void main(String[] args) {
JFrame frame = new JFrame("Rock Paper Scissors");
JPanel panel = new JPanel();
JLabel label = new JLabel("<html>Will you choose <i>rock,</i> <i>paper,</i> or <i>scissors?</i></html>");
JButton button = new JButton("I am a button.");
label.setHorizontalAlignment(0);
label.setVerticalAlignment(1);
panel.add(button); <-add button to panel
frame.add(panel, BorderLayout.SOUTH); <--- you need to say where you are adding the panel onto the frame.
frame.add(label,BorderLayout.NORTH); <--- same with the label
frame.pack();
frame.setTitle("Rock Paper Scissors");
frame.setSize(640, 480);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
button.setToolTipText("Y U no click me?");;
}
}
If you want a bigger button in the center, you can modify with this:
button.setPreferredSize(new Dimension(300, 300));
panel.add(button);
frame.add(panel, BorderLayout.CENTER); <--adds to center rather than south

Java Swing simple center of JPanel in other JPanel

I have this incredibly easy task of wanting a nice centered JPanel inside another JPanel. The parent is set to 900, 550, and the child should be approximately 200,400 or so.
To do this, I thought giving the parent a BorderLayout and then setting the setPreferredSize(200, 400) of the child. This child would be in the CENTER. Two empty JPanels would be on the EAST and WEST. Of course this did not work. Giving the two sidepanels a setPreferredSize() of course DID work. Problem with this is that narrowing the Frame causes the center pane to go away.
Here's some sample code that should give show the issue:
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Temporary {
public static Temporary myObj = null;
private JFrame mainFrame;
public void go(){
mainFrame = new JFrame("Swing");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setPreferredSize(new Dimension(900,550));
JPanel mainCards = new JPanel(new CardLayout());
mainCards.add(loginLayer(), "Login");
mainFrame.setContentPane(mainCards);
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
public JPanel loginLayer(){
JPanel masterPane = new JPanel(new BorderLayout());
JPanel centerPane = new JPanel();
centerPane.setLayout(new BoxLayout(centerPane, BoxLayout.Y_AXIS));
centerPane.setPreferredSize(new Dimension(100,200));
JLabel label = new JLabel("Swing is overly");
label.setAlignmentX(Component.CENTER_ALIGNMENT);
centerPane.add(label);
JButton button = new JButton("complicated");
button.setAlignmentX(Component.CENTER_ALIGNMENT);
centerPane.add(button);
JTextField textField = new JTextField(10);
centerPane.add(textField);
JPanel filler = new JPanel();
JPanel filler2 = new JPanel();
masterPane.add(filler, BorderLayout.WEST);
masterPane.add(centerPane, BorderLayout.CENTER);
masterPane.add(filler2, BorderLayout.EAST);
return masterPane;
}
public static void main(String[] args){
myObj = new Temporary();
myObj.go();
}
}
BorderLayout will, by it's nature, give as much of the available space as it can to the CENTER component. This is how it's designed.
If you want the component to be centered within the parent container, BUT maintain it's preferred size, you should consider using a GridBagLayout instead. Without any additional constraints, this should achieve the result you're after
For example...
public JPanel loginLayer(){
JPanel masterPane = new JPanel(new GridBagLayout);
JPanel centerPane = new JPanel();
centerPane.setLayout(new BoxLayout(centerPane, BoxLayout.Y_AXIS));
JLabel label = new JLabel("Swing is overly");
label.setAlignmentX(Component.CENTER_ALIGNMENT);
centerPane.add(label);
JButton button = new JButton("complicated");
button.setAlignmentX(Component.CENTER_ALIGNMENT);
centerPane.add(button);
JTextField textField = new JTextField(10);
centerPane.add(textField);
masterPane.add(centerPane);
// Add additional borders to providing padding around the center pane
// as you need
return masterPane;
}
I would also avoid actively setting the preferred size of component in this way, as it's possible that the components you're adding to it will exceed your expectations, instead, make use of things like EmptyBorder (for example) to add additional white space arouond the component and it's contents
In Java Swing, you generally want to avoid creating a bunch of statically positioned items with preferred sizes and absolute positions, because things get weird with resizing (as you've noticed). Instead you want to rely on the fluid LayoutManagers. There is an excellent tutorial here. Or, if you want to supply a mock-up of some sort to show the actual UI you are trying to create, I could provide some more feedback.

Categories

Resources