public class InputPanel extends JPanel{
public static int shapeType; //1: Rectangle; 2: Oval; 3: Line
public static boolean isFilled; //whether or not the shape is filled
public static Color color; //color of the shape
public InputPanel(){
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
panel.setBackground(Color.GRAY);
setPreferredSize(new Dimension(200,500));
JButton rect = new JButton("Rectangle");
JButton oval = new JButton("Oval");
JButton line = new JButton("Line");
JRadioButton fill = new JRadioButton("Filled:");
JButton color1 = new JButton("Color..");
rect.addActionListener(new rectListener());
oval.addActionListener(new ovalListener());
line.addActionListener(new lineListener());
isFilled = fill.isSelected();
color1.addActionListener(new colorListener());
panel.add(rect);
panel.add(oval);
panel.add(line);
panel.add(fill);
panel.add(color1);
this.setVisible(true);
}
}
public class PaintPanel extends JPanel{
public static int x1, y1, x2, y2;
ArrayList<Shape> shapeList = new ArrayList<Shape>();
public PaintPanel(){
JPanel panel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
panel.setBackground(Color.WHITE);
setPreferredSize(new Dimension(500, 500));
this.addMouseListener(new MouseAdapter() {
#Override public void mousePressed(MouseEvent e) {
PaintPanel.x1 = e.getX();
PaintPanel.y1 = e.getY();
}
#Override public void mouseReleased(MouseEvent e) {
PaintPanel.x2 = e.getX();
PaintPanel.y2 = e.getY();
if(InputPanel.shapeType == 1){
shapeList.add(new Rectangle(PaintPanel.x1, PaintPanel.y1, PaintPanel.x2, PaintPanel.y2, InputPanel.isFilled));
}
if(InputPanel.shapeType == 2){
shapeList.add(new Oval(PaintPanel.x1, PaintPanel.y1, PaintPanel.x2, PaintPanel.y2, InputPanel.isFilled));
}
if(InputPanel.shapeType == 3){
shapeList.add(new Line(PaintPanel.x1, PaintPanel.y1, PaintPanel.x2, PaintPanel.y2));
}
repaint();
}
});
this.setVisible(true);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
for(Shape s : shapeList){
s.draw(g);
}
}
}
public class PaintGUI {
public static void main(String[] args){
JFrame frame = new JFrame("Shape Drawer!");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new InputPanel());
frame.add(new PaintPanel());
frame.pack();
frame.setVisible(true);
}
}
I'm positive I've created the JFrame properly and all of my other classes work, but there must be something in here I'm missing...
When I run the main method all I get is a gray box that is clearly a square (500x500, as instantiated in the PaintPanel class. What am I doing wrong?
Apart from what Andrew mentioned, I noticed that within both your InputPanel and PaintPanel you're creating a new JPanel. You're adding new components to this panel, for sure, but at the end you're not adding this JPanel itself to your InputPanel or PaintPanel. So, make sure that in your constructors for these panels you have a add(panel) at the end.
Also, as a side note, do please keep in mind that most operations in Swing are not thread-safe and so read about "Concurrency in Swing" before creating/interacting with UI components. In other words, any updates to the user interface must happen on the event dispatch thread, like the start-up of your application:
public static void main(String[] args){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Shape Drawer!");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//set the layout, add your panels
frame.pack();
frame.setVisible(true);
}
});
}
JFrame by default uses BorderLayout.
frame.add(new InputPanel());
frame.add(new PaintPanel());
is equivalent to saying,
frame.add(new InputPanel(), BorderLayout.CENTER);
frame.add(new PaintPanel(), BorderLayout.CENTER);
The net result being that the Panel that is added last would be the one that is visible, provided the rest of your code is working correctly.
Must add the panel to the frame, use:
this.add(panel);
Related
I'm currently trying to create a primitive HUD inside a JFramewindow for a test game I am working on. In the course of doing this, all my attempts have been thwarted. Either the panel which contains all the buttons that are meant to represent the HUD does not display, or, the Canvas I attempt to draw to appears to not exist as no graphics I draw to it appear.
What I believe the problem is, is that the layers are not 'overlapping', and thus one is blocking out the other. However, I tried using a Flowlayout()(just for testing purposes) & that still did not fix my issue. So right now, I am at a loss for trying to have a HUD of buttons/Labels.
For visual purposes, I am trying to do something like this:
But I am actually getting this (just a test drawn tile, no HUD):
Here is the code that is involved:
public static void createDrawFrame(int width, int height) {
f = new JFrame();
c = new Canvas();
c.setPreferredSize(new Dimension(width, height));
c.setFocusable(false);
f.add(c);
f.pack();
f.setSize(width, height);
f.setLocationRelativeTo(null);
And
public static JFrame getDrawFrame() {
f.setVisible(true);
return f;
}
And
public static JFrame createHUD(JFrame f, Game game) {
Panel p = new Panel();
p.setLayout(new FlowLayout());
p.setSize(100, 100);
p.setLocation(300, 0);
Button b0 = new Button("Settings");
Button b1 = new Button("Exit");
MenuListeners mListeners = new MenuListeners(game);
b0.addActionListener(mListeners);
b1.addActionListener(mListeners);
p.add(b0);
p.add(b1);
f.add(p);
return f;
}
are called here:
private void init() {
Display.createDrawFrame(width, height);
Display.createMenuFrame(width, height);
this.f = Display.getDrawFrame();
this.c = Display.getCanvas();
this.f = HUDDisplay.createHUD(this.f, this);
MapAssets.init();
}
And are rendered here:
private void render() {
b = c.getBufferStrategy();
if(b == null) {
c.createBufferStrategy(3);
return;
}
do {
do {
g = b.getDrawGraphics();
g.clearRect(0, 0, width, height);
state.render(g);
b.show();
}while(b.contentsLost());
g.dispose();
}while(b.contentsRestored());
}
Hopefully I illustrated this problem correctly. To recap, I just want to know why my buttons are not displaying within the JFrame as they should be. Thanks for any help.
I think you can use JFrame's add method with BorderLayout to position the canvas and the buttons. I changed your code to show (demonstrate) it can be done. I hope it is what you are looking for.
I added the components (Canvas and Panel with buttons) to the JFrame using code like this to make them visible:
frame.add(panel, BorderLayout.NORTH); // panel with buttons
frame.add(canvas, BorderLayout.CENTER);
Here are links to Oracle's Java tutorials on Swing for further details; see the sections on Swing Components and Laying Out Components Within a Container.
Example code:
import java.awt.*;
import javax.swing.*;
public class FrameLayoutTest {
private static JFrame f;
private static Canvas c;
public static void main(String [] args) {
init();
}
private static void init() {
//Display.createDrawFrame(width, height);
createDrawFrame(400, 400);
//Display.createMenuFrame(width, height);
createHUD();
//this.f = Display.getDrawFrame();
//getDrawFrame();
//this.c = Display.getCanvas();
//this.f = createHUD(this.f, this);
//MapAssets.init();
}
public static void createDrawFrame(int width, int height) {
f = new JFrame();
c = new Canvas();
c.setBackground(Color.blue);
c.setPreferredSize(new Dimension(width, height));
c.setFocusable(false);
f.add(c, BorderLayout.CENTER); //f.add(c);
f.pack();
f.setVisible(true); // getDrawFrame()
f.setSize(width, height);
f.setLocationRelativeTo(null);
}
public static void createHUD() {
Panel p = new Panel();
p.setLayout(new FlowLayout());
p.setSize(100, 100);
p.setLocation(300, 0);
Button b0 = new Button("Settings");
Button b1 = new Button("Exit");
//MenuListeners mListeners = new MenuListeners(game);
//b0.addActionListener(mListeners);
//b1.addActionListener(mListeners);
p.add(b0);
p.add(b1);
f.add(p, BorderLayout.NORTH); //f.add(p);
}
}
I'm new to java and I'm trying to figure out how action listeners and buttons work. I've found that I can get a working JButton if I put it directly into my JFrame object. But if I put it in a JPanel within that JFrame, it won't respond. Why is that?
Main.java
public class Main {
private static Frame f = new Frame();
public static void main(String[] args) {}
}
Frame.java
public class Frame extends JFrame {
private final int WIDTH = 640, HEIGHT = 480;
private Panel p = new Panel();
Frame() {
super("Java Program");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(WIDTH, HEIGHT);
this.setLayout(null);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public void paint(Graphics g) {
super.paint(g);
p.paintComponent(g);
}
}
Panel.java
public class Panel extends JPanel {
JButton b = new JButton("Button");
Panel() {
b.setBounds(0, 0, 200, 100);
add(b);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
b.setText("Pressed");
}
});
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
b.paint(g);
}
}
I am not a Swing expert so I can't really explain why it does not work. It seems like an unresponsive button is painted on top of you button. I tweaked it a little and here are a few modifications to get it to work:
Add the panel to the Frame: add(p);
Remove the this.setLayout(null); line, it seems to mess up the frame
To set the size of the Frame, use setPreferredSize: this.setPreferredSize(new Dimension(WIDTH, HEIGHT));
You also need to call pack() at then end of your Frame constructor.
And you need to remove b.paint(g) from your Panel.paintComponent(), this seems to be what paints the "unresponsive" button, (see image at the end of the answer).
Optionally, you can remove the paint() from the Frame, it does nothing more than the JFrame's one
Here is a modified working version:
class Frame extends JFrame {
private final int WIDTH = 640, HEIGHT = 480;
private Panel p = new Panel();
Frame() {
super("Java Program");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setPreferredSize(new Dimension(WIDTH, HEIGHT));
this.setLocationRelativeTo(null);
this.setVisible(true);
// add the panel to the frame
add(p);
pack();
}
}
class Panel extends JPanel {
JButton b = new JButton("Button");
Panel() {
b.setBounds(0, 0, 200, 100);
add(b);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
b.setText("Pressed");
}
});
}
// You can also get rid of this method,
// I just leave it here to show that I removed the b.paint(g) line
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
}
Here is what the same code shows if you leave b.paint(g) in Panel.paintComponent(), as you can see there are 2 buttons, the one in the corner does not work.
I have one "main" panel. I'd like to have a "side" panel inside the main one. The side is composed of two other panels, let's call one graphicPanel and one supportPanel. I'm trying to add labels to the SupportPanel from the main one, but no changes happen.
Here is my side panel:
public class LateralSupportPane extends JPanel{
private final static int WIDTH = 240;
private final static int HEIGHT = 740;
private GraphicPanel gp;
private SupportPanel sp;
public LateralSupportPane(){
this.gp = new GraphicPanel();
this.sp = new SupportPanel();
this.setPreferredSize(new Dimension(WIDTH, HEIGHT));
this.setLayout(new GridLayout(2, 1));
//this.setBorder(BorderFactory.createLineBorder(Color.black));
this.add(gp);
this.add(sp);
this.setVisible(true);
}
public void addLabel(String label){
sp.addLabel(label);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
gp.paintComponent(g);
}
public void addLabel(String label){
sp.addLabel(label);
}
Here my supportPanel:
public class SupportPanel extends JPanel{
private JLabel label;
private final static int WIDTH = 240;
private final static int HEIGHT = 370;
public SupportPanel(){
this.setPreferredSize(new Dimension(WIDTH, HEIGHT));
label = new JLabel();
label.setText("<html>BlaBla</html>");
this.setLayout(new GridLayout(10, 1));
this.add(label);
this.setVisible(true);
}
public JLabel getLabel() {
return label;
}
public void addLabel(String text){
JLabel label = new JLabel(text);
if(this.getComponentCount() < 10){
this.add(label);
} else {
this.remove(0);
this.add(label);
}
}
From the main panel I call the addLabel of the side panel.
EDIT: Here is the frame with all panels. The board itself is a panel added into a frame. The board also has another panel, that are the black rectangle and the area where the string is, together. Then the side panel is composed by 2 other panels, the GraphicPanel (the black rectangle) and the supportPanel, that is the area where I'd like to have my labels.
Board
Validating all panels made no progress.
Not sure if i undurstend it correctly, but it seams, that you have to validate your panels after inserting new label;
public static void main(String[] args) {
JFrame frame = new JFrame("test");
frame.setSize(900, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new CardLayout());
frame.setVisible(true);
LateralSupportPane p = new LateralSupportPane();
frame.add(p);
frame.validate();
p.addLabel("test 2");
p.validate();
}
as you see, after adding a label, validation is performed and object is painted on form.
your method addLabel(String label) should have this method called at end of it.
Please take a look at the following code (I've missed the imports purposely)
public class MainFrame extends JFrame {
private JPanel contentPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MainFrame frame = new MainFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MainFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
tabbedPane.setBounds(10, 11, 414, 240);
contentPane.add(tabbedPane);
JPanel panel = new JPanel();
panel.addFocusListener(new FocusListener() {
#Override
public void focusLost(FocusEvent arg0) {
System.out.println("lost");
// I want to do something here, if I reach here!
}
#Override
public void focusGained(FocusEvent arg0) {
System.out.println("gained");
// I want to do something here, if I reach here!
}
});
tabbedPane.addTab("New tab", null, panel, null);
JButton button = new JButton("New button");
panel.add(button);
JPanel panel_1 = new JPanel();
tabbedPane.addTab("New tab", null, panel_1, null);
JPanel panel_2 = new JPanel();
tabbedPane.addTab("New tab", null, panel_2, null);
}
}
I've created this class to test it and then add the onFocusListener in my main code, but it's not working the way I expect. Please tell what's wrong or is this the right EvenetListener at all?
JPanels are not focusable by default. If you ever wanted to use a FocusListener on them, you'd first have to change this property via setFocusable(true).
But even if you do this, a FocusListener is not what you want.
Instead I'd look to listen to the JTabbedPane's model for changes. It uses a SingleSelectionModel, and you can add a ChangeListener to this model, listen for changes, check the component that is currently being displayed and if your component, react.
You are using setBounds and null layouts, something that you will want to avoid doing if you are planning on creating and maintaining anything more than a toy Swing program.
Edit
For example:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.*;
import javax.swing.event.*;
#SuppressWarnings("serial")
public class MainPanel extends JPanel {
private static final int PREF_W = 450;
private static final int PREF_H = 300;
private static final int GAP = 5;
private static final int TAB_COUNT = 5;
private JTabbedPane tabbedPane = new JTabbedPane();
public MainPanel() {
for (int i = 0; i < TAB_COUNT; i++) {
JPanel panel = new JPanel();
panel.add(new JButton("Button " + (i + 1)));
panel.setName("Panel " + (i + 1));
tabbedPane.add(panel.getName(), panel);
}
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setLayout(new BorderLayout());
add(tabbedPane, BorderLayout.CENTER);
tabbedPane.getModel().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent evt) {
Component component = tabbedPane.getSelectedComponent();
System.out.println("Component Selected: " + component.getName());
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
MainPanel mainPanel = new MainPanel();
JFrame frame = new JFrame("MainPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
JPanel is a lightweight container and it is not a Actionable component so it does not get focus events. It lets you add focus listener because of swing component hierarchy. In Order to get tab selected events you need to use JTabbedPane#addChangeListener.
Hope this helps.
well I've had a few tips on using the splitpane to split my frame into two areas, but I can't manage to get it to show something useful. The code looks as follows:
public class Whiteboard extends JPanel {
int width = 600;
int sidePanelWidth = 200;
int lineHeight = 120;
int numberOfLines = 5;
JFrame frame = null;
Glyph glyph = null;
//java.awt.Rectangle bounds = new java.awt.Rectangle();
Bounds bounds = null;
JSplitPane splitPane = null;
JPanel tools = null;
public Whiteboard() {
frame = new JFrame();
frame.setSize(width + sidePanelWidth, getFullHeight());
FlowLayout simpleLayout = new FlowLayout();
frame.setLayout(simpleLayout);
tools = new JPanel();
tools.setSize(new Dimension(sidePanelWidth, getFullHeight()));
this.setSize(width, getFullHeight());
splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, this, tools);
splitPane.setPreferredSize(new Dimension(width + sidePanelWidth, getFullHeight()));
splitPane.setOneTouchExpandable(false);
splitPane.setDividerLocation(150);
frame.add(splitPane);
this.setBackground(Color.white);
java.awt.Rectangle rectBounds = this.getBounds();
bounds = new Bounds((int)rectBounds.getX(), (int)rectBounds.getY(), (int)(rectBounds.getX() + rectBounds.getWidth()), (int)(rectBounds.getY() + rectBounds.getHeight()));
}
public int getFullHeight() {
return lineHeight * numberOfLines;
}
I changed now the code like this:
public static void main(String[] args) {
int sidePanelWidth = 200;
JFrame frame = new JFrame();
Whiteboard whiteboard = new Whiteboard();
JPanel sidePanel = new JPanel();
sidePanel.setPreferredSize(new Dimension(sidePanelWidth, whiteboard.getFullHeight()));
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
splitPane.add(whiteboard, JSplitPane.LEFT);
splitPane.add(sidePanel, JSplitPane.RIGHT);
frame.setLayout(new FlowLayout());
frame.getContentPane().add(splitPane);
frame.pack();
frame.setVisible(true);
whiteboard.repaint();
}
And the constructor to this:
public Whiteboard() {
this.setPreferredSize(new Dimension(width, getFullHeight()));
this.setBackground(Color.red);
}
Now I don't know where the problem is, maybe it's because it doesn't call the paintComponent method. I tried forcing it by calling repaint() it doesn't help, it just doesn't call this componenent
Edit: Well now it seems it is calling the paintComponent method after all, but still I get the screen like this:
As you can see, it's not looking so good. Well the code of my current main Method:
public static void main(String[] args) {
int sidePanelWidth = 200;
JFrame frame = new JFrame();
Whiteboard whiteboard = new Whiteboard();
JPanel sidePanel = new JPanel();
sidePanel.setPreferredSize(new Dimension(sidePanelWidth, whiteboard.getFullHeight()));
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
splitPane.add(whiteboard, JSplitPane.LEFT);
splitPane.add(sidePanel, JSplitPane.RIGHT);
frame.setLayout(new FlowLayout());
frame.getContentPane().add(splitPane);
frame.pack();
frame.setVisible(true);
whiteboard.repaint();
}
Any idea how to change it to fix the problem? Do I need to post other methods?
Creating a JFrame from within the constructor of a JPanel should really not be done.
Here is an example I created:
import java.awt.Container;
import java.awt.Dimension;
import javax.swing.*;
public class JavaApplication100 {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JavaApplication100().createAndShowUI();
}
});
}
private void createAndShowUI() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initComponents(frame.getContentPane());
frame.pack();
frame.setVisible(true);
}
private void initComponents(Container contentPane) {
JPanel mainPanel = new JPanel();
//create our 2 seperate panels (could be custom ones)
JPanel leftPanel = new JPanel();
JPanel rightPanel = new JPanel();
//add labels for viewing
leftPanel.add(new JLabel("LEFT"));
rightPanel.add(new JLabel("RIGHT"));
//just so you can see em or they would be small
leftPanel.setPreferredSize(new Dimension(300, 300));
rightPanel.setPreferredSize(new Dimension(300, 300));
JSplitPane jsp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
//add panels to split pane
jsp.add(rightPanel, JSplitPane.RIGHT);
jsp.add(leftPanel, JSplitPane.LEFT);
mainPanel.add(jsp);//add splitpane to mainpanel
contentPane.add(mainPanel);
}
}
EDIT/UPDATE:
as per your comment if you want to colour the background override paintComponent(Graphics g) in your WhiteBoard which extendsJPanel like so:
public class WhiteBoard extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.fillRect(0, 0, getWidth(), getHeight());
}
}
You could use JSplitPane.setDividerLocation(int) instead...
public class TestSplitPane extends JFrame {
public TestSplitPane() throws HeadlessException {
setSize(600, 600);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new BorderLayout());
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
splitPane.setLeftComponent(new JLabel("I'm on the left"));
splitPane.setRightComponent(new JLabel("I'm on the right"));
add(splitPane);
splitPane.setDividerLocation(200);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
new TestSplitPane().setVisible(true);
}
});
}
}