jsplitpane and paintcomponent conflicting with each other - java

I'm having issues with my code regarding the fact that when I instantiate my City class as an object and add it to the right side of my JSplitPane (or even the left), the circle that is supposed to be drawn is not showing up. My cities class uses paintComponent and should draw a circle just by calling the constructor. I have also tried putting the repaint in its own drawIt() method but the result is still the same. The buttons and spinner show up on the left side of the divider, but the circle I am trying to draw does not show up at all.
Here is my City class.
import javax.swing.*;
import java.awt.*;
public class City extends JPanel{
int xPos, yPos;
City(int x, int y){
xPos = x;
yPos = y;
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillOval(xPos, yPos, 10, 10);
}
}
And here is my main.
Here I try to instantiate my city and add it to the right side of the JSplitPane (under Add Components) and that is where I am having issues with, as the black circle will not be drawn on the JSplitPane.
import java.awt.*;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JSplitPane;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
public class TSP{
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TSP();
}
});
}
TSP(){
JLabel instructions = new JLabel("Enter the number of cities: ");
instructions.setBounds(30, 150, 300, 40);
SpinnerNumberModel numMod = new SpinnerNumberModel(2, 2, 10, 1);
JSpinner numOfCities = new JSpinner(numMod);
numOfCities.setBounds(185, 150, 80, 40);
JButton start = new JButton("Start Simulation");
start.setBounds(50, 400, 200, 40);
JFrame frame = new JFrame("Travelling Salesperson");
JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
JPanel lp = new JPanel(null);
JPanel rp = new JPanel(null);
sp.setDividerLocation(300);
sp.setLeftComponent(lp);
sp.setRightComponent(rp);
sp.setEnabled(false);
frame.setDefaultCloseOperation(3);
frame.setSize(1100,600);
frame.setResizable(false);
////////////////Add Components//////////////////////////
lp.add(instructions);
lp.add(numOfCities);
lp.add(start);
City test = new City(301, 301);
rp.add(test);
frame.add(sp);
////////////////////////////////////////////////////////
frame.setVisible(true);
}
}
I feel like the circle is being drawn under the JSplitPane as if I add my cities object (test) to my frame instead of the JSplitPane(frame.add(test) instead of rp.add(test) under the Add Components section) the black circle will appear in the desired spot but the JSplitPane along with the buttons and spinners will disappear so I feel as if they are conflicting. Is there any fix to this or is there another way altogether to make the circle appear on the right side while the other components are on the left side.
I do not know why it is not drawing the circle on the JSplitPane, but any sort of help would be appreciated. Thanks!
Sorry if anything is unclear or there is any ambiguity in my code, or if I need to post more information as I am quite new to posting here. Let me know if there is anything else I need to add or if there are any questions regarding what I am asking!
EDIT:
It seems there is something blocking where I draw the circle, like another JPanel. Here is an image below. As you can see part of the circle looks as if it is being covered. The small box I drew is the only area that the dot is visible from (everywhere else the circle is covered up by white). Also, the coordinates for the circle in the image below is at (3, 0), i.e City test = new City(3, 0);
I am not quite sure why this is happening though.
the invisible JPanel?

Now that I've seen what you're trying to do, I can provide a more proper answer.
You have a control panel on the left and a drawing panel on the right. Usually, you don't use a JSplitPane to separate the panels. To create your layout, you would add the control panel to the LINE_START of the JFrame BorderLayout and the drawing panel to the CENTER.
The reason for this is that you don't want to constantly recalculate the size of the drawing panel.
So let me show you one way to get a solid start. Here's the GUI I created.
Here are the things I did.
All Swing GUI applications must start with a call to the SwingUtilities invokeLater method. This method ensures that Swing components are created and executed on the Event Dispatch Thread.
I separated the creation of the JFrame, the control panel, and the drawing panel. That way, I could focus on one part of the GUI at a time.
The JFrame methods must be called in a certain order. This is the order that I use for most of my Swing applications.
The JFrame is not sized. It is packed. The Swing layout managers will calculate the size of the components and the JPanels.
I used a FlowLayout and a GridBagLayout to create the control panel. Yes, this looks more complicated than absolute positioning, but in the long run, layout managers allow the GUI to be more flexible.
I used the setPreferredSize method in the drawing panel to set the preferred size of the drawing panel. Because I know the drawing panel size, I can put the first city in the center of the drawing panel.
And here's the code. You don't have to code exactly like this, but this code should give you a good basis to start your project. Take a look at the model / view / controller pattern and see how to further separate your code into smaller pieces that allow you to focus on one part of your application at a time.
I put all the classes in one file to make it easier to paste. You should separate these classes into separate files.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
public class CitySimulation implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new CitySimulation());
}
private ControlPanel controlPanel;
private DrawingPanel drawingPanel;
private JFrame frame;
#Override
public void run() {
frame = new JFrame("Traveling Salesperson");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
controlPanel = new ControlPanel();
frame.add(controlPanel.getPanel(), BorderLayout.LINE_START);
drawingPanel = new DrawingPanel();
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class ControlPanel {
private JPanel panel;
public ControlPanel() {
panel = new JPanel(new FlowLayout());
JPanel mainPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.LINE_START;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(10, 10, 10, 10);
JLabel instructions = new JLabel("Enter the number " +
"of cities:");
mainPanel.add(instructions, gbc);
gbc.gridx++;
gbc.insets = new Insets(10, 0, 10, 10);
SpinnerNumberModel numMod =
new SpinnerNumberModel(2, 2, 10, 1);
JSpinner numOfCities = new JSpinner(numMod);
mainPanel.add(numOfCities, gbc);
gbc.anchor = GridBagConstraints.CENTER;
gbc.gridx = 0;
gbc.gridy++;
gbc.gridwidth = 2;
gbc.insets = new Insets(10, 10, 10, 10);
JButton start = new JButton("Start Simulation");
mainPanel.add(start, gbc);
panel.add(mainPanel);
}
public JPanel getPanel() {
return panel;
}
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
public DrawingPanel() {
this.setBackground(Color.WHITE);
this.setPreferredSize(new Dimension(400, 400));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillOval(195, 195, 10, 10);
}
}
}

Related

How to choose the best layouts for nested JPanels?

I plan to design a gui program which contains the one outer JPanel which contains a lot of recurring JPanel which has text and button.Yet , I couldn't decide which layouts are suitable for this task.I want it to be like this :
I just copied and pasted first JPanel which will be recurred programmatically like you see in the image.
Which layouts should I use in order to get a result like this ?
In my head it looks like this:
JScrollPane > JPanel (outerPane) > JPanel (innerPane [many])
Based on this, we need to think which layout manager is the outerPane going to use and the innerPanes...
In order to provide spacing between innerPanes I would go for GridLayout (rows, columns, hgap, vgap) like:
GridLayout(0, 1, 5, 5);
Now for each innerPane we could go for GridLayout, GridBagLayout or FlowLayout, let's see what would happen with each:
If we used FlowLayout the components wouldn't be in a "grid" or "table" like layout, so, it's a no no... this is how it would look like:
Altough they seem like what we need, I'm not sure if each label is going to change over time or not, but you could try...
Using GridLayout would make our JButtons to take the whole space of the cell, and it wouldn't look good (at least when resizing it), here's an image with the before and after resizing the GUI to show what I mean (cropped to not use a lot of space in the post):
If your GUI won't resize you can go with this path, if it will, then you should another layout.
GridBagLayout is my favorite in this case because each label will stay in their own column and the buttons won't fill all the available space and our GUI will look more like the image you posted:
In the example above, I used a CustomBorder class to provide spacing between the innerPanes and the outerPane while also providing a a colored border as well as showing the vertical JScrollPane always.
The code that produces those outputs is:
package sof;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.geom.Rectangle2D;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.border.AbstractBorder;
public class NestedPanels {
private JFrame frame;
private JPanel outerPane;
private JPanel innerPane;
private GridBagConstraints gbc;
private JScrollPane scrollPane;
public static void main(String[] args) {
SwingUtilities.invokeLater(new NestedPanels()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
outerPane = new JPanel();
outerPane.setLayout(new GridLayout(0, 1, 5, 5));
for (int i = 0; i < 5; i++) {
innerPane = new JPanel();
innerPane.setLayout(new GridBagLayout());
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.fill = GridBagConstraints.BOTH;
gbc.insets = new Insets(10, 10, 10, 10);
innerPane.add(new JLabel("Recurring JLabel1"), gbc);
gbc.gridx++;
innerPane.add(new JLabel("Recurring JLabel2"), gbc);
gbc.gridx++;
innerPane.add(new JLabel("Recurring JLabel3"), gbc);
gbc.gridx++;
innerPane.add(new JButton("Recurring JButton1"), gbc);
innerPane.setBorder(BorderFactory.createLineBorder(Color.BLACK));
outerPane.add(innerPane);
}
outerPane.setBorder(new CustomBorder(5, Color.BLACK));
scrollPane = new JScrollPane(outerPane, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
frame.add(scrollPane);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#SuppressWarnings("serial")
class CustomBorder extends AbstractBorder {
private int gap;
private Color color;
public CustomBorder(int gap, Color color) {
this.gap = gap;
this.color = color;
}
#Override
public Insets getBorderInsets(Component c) {
return new Insets(gap, gap, gap, gap);
}
#Override
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
super.paintBorder(c, g, x, y, width, height);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(color);
g2d.draw(new Rectangle2D.Double(x, y, width - 1, height - 1));
}
}
}
Play with the border styles to get the desired one, I painted the border with a -1 pixel on the GUI, if I didn't it would only show left and top borders...
Another option would be using a JTable but I leave that to you

Java dynamically changing components when scrollbar appears

I'm trying to implement a feature that (in my test project) once a button is pressed, it adds a random number to my JPanel. (I use the layouts I have because in my real program, I have more items inside and it displays correctly). But I need my program to recognize when the scrollbar is visible (which I implemented that, but it's a little delay. What I mean by delay is I push the button to add a number, if the scrollbar becomes visible nothing happens. But then the next time I press the button it shifts over like I want). The other problem I have (the one I'm focused on now) is that when I dynamically change the size of the JPanel, if the scrollbar is visible, I have it set to change the width to my width - the width of the scrollbar. But It seems like when the scrollbar is visible, the newly inputted number moves over twice the scrollbar width instead of just once. I've been at this part of my program for over a day and can't figure it out. I'll add my full code and some screenshots.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Main {
JFrame frame;
JPanel topPanel;
JPanel memoryPanel;
JScrollPane sPane;
JButton button;
ArrayList<Integer> list = new ArrayList<>();
boolean isVScrollVisible = false;
int scrollBarSize = 0;
public class MyChangeListener implements ChangeListener {
#Override
public void stateChanged(ChangeEvent e) {
isVScrollVisible = (sPane.getVerticalScrollBar().isVisible());
}
}
public class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
Random random = new Random();
int r = random.nextInt(10);
list.add(r);
int n;
if (isVScrollVisible) {
n = scrollBarSize;
} else {
n = 0;
}
JPanel nextPanel = new JPanel();
nextPanel.setName("" + r);
nextPanel.setForeground(Color.BLACK);
nextPanel.setPreferredSize(new Dimension(200 - n, 55));
nextPanel.setMinimumSize(new Dimension(200 - n, 55));
nextPanel.setMaximumSize(new Dimension(200 - n, 55));
JPanel labelPanel = new JPanel();
labelPanel.setLayout(new BorderLayout());
JLabel label = new JLabel();
label.setText("" + r);
label.setPreferredSize(new Dimension(200 - n, 55));
label.setMinimumSize(new Dimension(200 - n, 55));
label.setMaximumSize(new Dimension(200 - n, 55));
label.setHorizontalAlignment(JLabel.RIGHT);
label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 17));
label.setFont(new Font("Sans-Serif", Font.BOLD, 20));
labelPanel.add(label);
nextPanel.add(labelPanel, BorderLayout.LINE_START);
for (int i = 0; i < memoryPanel.getComponents().length; i++) {
memoryPanel.getComponent(i).setPreferredSize(new Dimension(200 - n, 55));
memoryPanel.getComponent(i).revalidate();
memoryPanel.getComponent(i).repaint();
}
memoryPanel.add(nextPanel, 0);
memoryPanel.revalidate();
memoryPanel.repaint();
sPane.revalidate();
sPane.repaint();
}
}
public Main() {
frame = new JFrame();
topPanel = new JPanel();
memoryPanel = new JPanel();
memoryPanel.setLayout(new BoxLayout(memoryPanel, BoxLayout.Y_AXIS));
sPane = new JScrollPane(memoryPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
sPane.setPreferredSize(new Dimension(200, 300));
sPane.getViewport().addChangeListener(new MyChangeListener());
scrollBarSize = ((Integer)UIManager.get("ScrollBar.width")) + 1;
button = new JButton("Add Random Number");
button.addActionListener(new ButtonListener());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
topPanel.add(button);
frame.add(topPanel, BorderLayout.PAGE_START);
frame.add(sPane, BorderLayout.CENTER);
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
new Main();
}
}
I need them to look exactly the same. Before I had the code I have now, the scrollbar would appear over the numbers which looked ugly. And the reason I have the frame resizable false is because In my real program I hard coded all the sizes, which in the future I will calculate the correct sizes based on the size of the frame, so right now setting resizable to true is out of the question. Any suggestions on what to do?
This is what I'm trying to accompolish.
Get rid of all the logic that sets the preferred/minimum/maximum sizes. Each component knows what its size should be. Each layout manager will in turn know what the preferred size of the panel should be. Let the layout manager use the information to do its job.
The basic logic for dynamically adding components is:
panel.add(...);
panel.revalidate();
panel.repaint();
Then the scrollbars will appear automatically when required. There is no need for listeners or anything.
Edit:
The reason I set all the sizes is because If I take them out then everything appears centered
Learn how to use layout managers properly and effectively.
For example when using a BoxLayout you can control the alignment of components by using:
component.setAlignmentX(JLabel.RIGHT_ALIGNMENT);
and the component will be aligned to the right edge of the space available to the component.
When using a JLabel you may also need to set a property on the JLabel to align the text to the right edge of the label. Read the JLabel API for the appropriate method.

Java Swing Moving Away From Null Layout

I built a great GUI using the frowned upon null layout (I defined a lot of constants and used a window resize listener to make it easy). Everything worked perfectly until I started using a new computer. Now, the component's are not positioned properly (from the picture you can see that the components are offset down and right). After researching the problem I learned that layout managers make sure that the components are positioned properly throughout different machines. Because of this, I would like to start rebuilding the GUI in an actual layout manager. The problem is that I often feel limited in the way I position components when attempting to use an actual layout manager.
For anyone who is curious, I was originally using a dell inspiron laptop with windows 10, and have moved to an Asus Laptop (I don't know the actual model, but the touch screen can detach from the keyboard), also with windows 10.
My question:
Which layout manager would be the fastest and easiest to build the GUI shown in the picture above (out of the stock Swing Layouts and others). I would like this layout to respect the components' actual sizes for only a few but not all of the components. Using this layout, how would I go about positioning the inventory button (the hammer at the bottom left) so that the bottom left corner of the inventory button is 5 pixels up and right from the bottom left corner of the container, even after resizing the container?
Thanks in advance. All help is appreciated.
EDIT: The "go find a key" and "Attempt to force the door open" options should have their sizes respected.
The simplest solution that comes to my mind is a BorderLayout for the main panel. Add the textarea to NORTH / PAGE_START. Make another BorderLayout containing the inventory button (WEST / LINE_START) and the location label (EAST / LINE_END). Add that to SOUTH / PAGE_END of the main BorderLayout. Then just add a BoxLayout with vertical alignment to the main BorderLayout's CENTER containing the two buttons. Here's a tutorial for the standard layout managers.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Insets;
import java.awt.image.BufferedImage;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class Example {
public Example() {
JTextArea textArea = new JTextArea("There is a locked door");
textArea.setRows(5);
textArea.setBorder(BorderFactory.createLineBorder(Color.GRAY));
textArea.setEditable(false);
WhiteButton button1 = new WhiteButton("Go find a key") {
#Override
public Dimension getMinimumSize() {
return new Dimension(200, 25);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 25);
}
#Override
public Dimension getMaximumSize() {
return new Dimension(200, 25);
}
};
WhiteButton button2 = new WhiteButton("Attempt to force the door open");
button2.setMargin(new Insets(0, 60, 0, 60));
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
buttonPanel.add(button1);
buttonPanel.add(Box.createVerticalStrut(5));
buttonPanel.add(button2);
WhiteButton inventoryButton = new WhiteButton(
new ImageIcon(new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB)));
JLabel locationLabel = new JLabel("Location: 0");
locationLabel.setVerticalAlignment(JLabel.BOTTOM);
JPanel southPanel = new JPanel(new BorderLayout());
southPanel.add(inventoryButton, BorderLayout.WEST);
southPanel.add(locationLabel, BorderLayout.EAST);
JPanel mainPanel = new JPanel(new BorderLayout(0, 5));
mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
mainPanel.add(textArea, BorderLayout.NORTH);
mainPanel.add(buttonPanel);
mainPanel.add(southPanel, BorderLayout.SOUTH);
JFrame frame = new JFrame("Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Example();
}
});
}
private class WhiteButton extends JButton {
public WhiteButton() {
setBackground(Color.WHITE);
}
public WhiteButton(String text) {
this();
setText(text);
}
public WhiteButton(ImageIcon icon) {
this();
setIcon(icon);
setBorder(BorderFactory.createLineBorder(Color.GRAY));
}
}
}

How can I place buttons in the center of the frame in a vertical line?

I will place these buttons in the center of the frame and above each other, like this.
BUTTON
BUTTON
BUTTON
I've searched multiple topics on this forum but everything I tried didn't work for so far. I hope that somebody has the solution.
This is my code for so far:
package ípsen1;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class Paneel extends JPanel implements ActionListener {
Image achtergrond;
private JButton spelHervatten;
private JButton spelOpslaan;
private JButton spelAfsluiten;
public Paneel(){
//buttons
spelHervatten = new JButton("Spel hervatten");
spelHervatten.setPreferredSize(new Dimension(380, 65));
spelOpslaan = new JButton("Spel opslaan");
spelOpslaan.setPreferredSize(new Dimension(380, 65));
spelAfsluiten = new JButton("Spel afsluiten");
spelAfsluiten.setPreferredSize(new Dimension(380, 65));
//object Paneel luistert naar button events
spelAfsluiten.addActionListener(this);
add (spelHervatten);
add (spelOpslaan);
add (spelAfsluiten);
}
public void paintComponent(Graphics g) {
//achtergrond afbeelding zetten
achtergrond = Toolkit.getDefaultToolkit().getImage("hout.jpg");
//screensize
g.drawImage(achtergrond, 0,0, 1024,768,this);
}
//actie na klik op button
public void actionPerformed(ActionEvent e) {
if(e.getSource() == spelAfsluiten){
System.out.println("Spel afsluiten");
System.exit(0);
}
}
}
You could use a GridBagLayout
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
add(new JButton("Button"), gbc);
add(new JButton("Button"), gbc);
add(new JButton("Button"), gbc);
add(new JButton("Button"), gbc);
See How to Use GridBagLayout for more details
A BoxLayout might be what you're after. You can specify that you want to add components along the y-axis in the constructor for that particular layout manager.
You could add this line to the constructor of your Paneel class.
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
As for center-aligning everything, I don't know if it's good practice but you can set the horizontal alignment for each of your buttons individually. Example:
spelHervatten.setAlignmentX(CENTER_ALIGNMENT);
Uses a GridLayout for a single column of buttons of equal width.
The buttons stretch as the window's size increases. To maintain the button size, put the GridLayout as a single component into a GridBagLayout with no constraint. It will be centered.
The size of the buttons is increased by setting a margin.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
/*
* Uses a GridLayout for a single column of buttons of equal width.
* The buttons stretch as the window's size increases. To maintain
* the button size, put the GridLayout as a single component into a
* GridBagLayout with no constraint. It will be centered.
*/
public class CenteredSingleColumnOfButtons {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
// the GUI as seen by the user (without frame)
JPanel gui = new JPanel(new GridLayout(0,1,10,10));
gui.setBorder(new EmptyBorder(20,30,20,30));
String[] buttonLabels = {
"Spel hervatten",
"Spel opslaan",
"Spel afsluiten"
};
Insets margin = new Insets(20,150,20,150);
JButton b = null;
for (String s : buttonLabels) {
b = new JButton(s);
b.setMargin(margin);
gui.add(b);
}
JFrame f = new JFrame("Centered Single Column of Buttons");
f.add(gui);
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See http://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
f.setMinimumSize(f.getSize());
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
System.out.println(b.getSize());
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
I thought there is no way to do that.
You should get size of Panel/Frame then calculate manually to find to center position for your button.
Rephrased some parts:
You might want to try to put the buttons in JFrame's "wind direction"-style BorderLayout:
http://www.leepoint.net/notes-java/GUI/layouts/20borderlayout.html
Just create a block in the CENTER with one EAST and WEST block with a certain size around it. Then insert the buttons inside of the center block. If you don't want them to be the full size, just add another EAST and WEST.

Creating a mouselistener over a single Jpane

it's my first post so I hope it'll not be too cringeworthy. So I am trying to create a hex-based strategy game, not quite there yet but anyways.
To achieve a hex-based game I would like to create a field made of hexes which the user should be able to click, and receive the coordinates of that pixel. At the moment I can produce either a field of hexes or a mouselistener/mouseadapter but not both. The last one executed replaces the other on the screen.
If the pane.add(New HexMap()); is switched with pane.add(new MouseListener()); the listener works but the line is not printed
I've looked around for quite some time but the posts that I've encountered had either dealt with changing the background color which the mouselistener can do, because background is independent of the mousesensorhttp://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html? The other examples I've come by have been too advanced for me, because they're using multiple panes, and I have not been able to comprehend themhttp://docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html.
So what I'm looking for is a way to add a mouselistener over a single pane, displaying the hexes. Would this be possible?
E.G adding the hexMap after the mouselistener would not overwrite the mouselistener but rather act as an addition
A single line has been created acting as a placeholder for the hexes.
The code:
import java.awt.*;
import java.awt.event.*;
import java.awt.font.*;
import java.awt.geom.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
public class GraphicsSetup extends JPanel{
public static final int FRAME_WIDTH = 600;
public static final int FRAME_HEIGHT= 400;
private static JFrame frame;
public static void main(String[] args){
GraphicsSetup draw = new GraphicsSetup();
}
public GraphicsSetup(){
HexMap hexMap = new HexMap();
JPanel panel = new JPanel();
frame = new JFrame("HexExample");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(FRAME_WIDTH,FRAME_HEIGHT);
Container pane = frame.getContentPane();
pane.setBackground(new Color(20, 100, 30));
pane.add(new MouseListener());
pane.add(new HexMap());
frame.setVisible(true);
}
public class HexMap extends JComponent{
public void paint(Graphics g){
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.blue);
g2d.drawLine(0,0, FRAME_WIDTH, FRAME_HEIGHT);
}
}
class MouseListener extends JComponent{
public MouseListener(){
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
System.out.println("Mouse Event" + me);
}
});
}
}
}
Yours Sincerely
I'm not entirely sure what you're after, but try adding your components to your panel object. Such as:
panel.add(new MouseListener());
panel.add(new HexMap());
And then add this to the content pane of your frame:
pane.add(panel);
If you're wondering how to arrange your interface differently, read about layout managers here:
http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
Edit
Try the following:
Set the layout manager to use a BorderLayout:
JPanel panel = new JPanel(new BorderLayout());
Add your components to the panel and set their location:
panel.add(new MouseListener(), BorderLayout.NORTH);
panel.add(new HexMap(), BorderLayout.CENTER);
Add the panel to the frame content pane:
pane.add(panel);
This will work but the size of the MouseListener panel is quite small...you'll need to figure that out next...

Categories

Resources