drawing in swing Java - java

I'm making the game "Who is millionaire".
This is the help panel, which let user choose one of the options such as: calling friend, asking audience, etc.
But I have a problem, the options are ellipses, which are drawn in class Help_Option extends JComponent. When I test this class Help_Option individually, it works fine. But when I add the Help_Option object into the game panel, actually a sub-panel in the frame, it just displays a line on the panel, it doesn't draw my ellipse.
This is my code:
Note: a is JFrame, I don't copy the whole method initialize(JFrame a) cos it's quite long and I don't think that the error comes from there.
/******Helper panel**********/
JPanel help_area_container = new JPanel();
help_area_container.setBorder(BorderFactory.createLineBorder(Color.BLUE, 3));
help_area_container.setLayout(new GridLayout(4,0));
JPanel voting_container = new JPanel();
JPanel calling_container = new JPanel();
JPanel half_container = new JPanel();
JPanel take_container = new JPanel();
JPanel[] all_help_container = new JPanel[]{voting_container, calling_container, half_container, take_container};
for(int i = 0; i < all_help_container.length; i++){
all_help_container[i].setBorder(BorderFactory.createLineBorder(Color.RED));
all_help_container[i].setPreferredSize(new Dimension(350, help_area_container.getPreferredSize().height/4));
}
for(int j = 0; j < all_help_container.length; j++){
help_area_container.add(all_help_container[j]);
}
Help_Option voting_option = new Help_Option(all_help_container[0].getPreferredSize().width, all_help_container[0].getPreferredSize().height);
voting_option.setPreferredSize(new Dimension(all_help_container[0].getPreferredSize().width, all_help_container[0].getPreferredSize().height));
all_help_container[0].add(voting_option);
a.add(help_area_container, BorderLayout.EAST);
/*****************************/
This is the Help_Option class:
class Help_Option extends JComponent implements MouseMotionListener{
private static int x, y;
private Ellipse2D ellipse;
private Color c = Color.BLACK;
public Help_Option(int x, int y){
Help_Option.x = x;
Help_Option.y = y;
ellipse = new Ellipse2D.Double(0, 0, x, y);
this.addMouseMotionListener(this);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.BLUE);
g2d.draw(ellipse);
g2d.setColor(c);
g2d.fill(ellipse);
g2d.setColor(Color.RED);
g2d.setFont(new Font("TimesRoman", Font.BOLD, 20));
g2d.drawString("Here I am", 250, 100);
}
public void setColor(Color c){
this.c = c;
}
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
if(ellipse.contains(e.getX(), e.getY())){
setColor(Color.GREEN);
repaint();
}else{
setColor(Color.BLACK);
repaint();
}
}
}
And this is the class that i used to test Help_Option class:
public class Help extends JFrame{
public static void main(String [] agrs){
Help h = new Help();
h.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
h.init();
}
public void init(){
this.setLayout(new FlowLayout());
this.setSize(2000, 1000);
JPanel a = new JPanel();
a.setPreferredSize(new Dimension((int)a.getSize().width/3, (int)a.getSize().height/2));
a.setBorder(BorderFactory.createLineBorder(Color.yellow, 3));
Help_Option k = new Help_Option(a.getPreferredSize().width, a.getPreferredSize().height/2);
k.setPreferredSize(new Dimension(a.getPreferredSize().width, a.getPreferredSize().height));
a.add(k);
this.add(a);
this.setVisible(true);
}
}
EDIT
This is the link to my classes, please take a look at them. The error is described above.

It is that you haven't set values for your first couple of JPanels and they are returning preferred sizes of 0. Dimensions of 0,0
So you should add values to the JPanels there.
public static void main(String[] args) {
JPanel help_area_container = new JPanel();
help_area_container.setBorder(BorderFactory.createLineBorder(
Color.BLUE, 3));
help_area_container.setLayout(new GridLayout(4, 0));
//Should have set sizes below
JPanel voting_container = new JPanel();
//voting_container.setSize(50,50);
JPanel calling_container = new JPanel();
JPanel half_container = new JPanel();
JPanel take_container = new JPanel();
JPanel[] all_help_container = new JPanel[] { voting_container,
calling_container, half_container, take_container };
for (int i = 0; i < all_help_container.length; i++) {
all_help_container[i].setBorder(BorderFactory
.createLineBorder(Color.RED));
all_help_container[i].setPreferredSize(new Dimension(350,
help_area_container.getPreferredSize().height / 4));
}
for (int i = 0; i < all_help_container.length; i++) {
System.out.println(all_help_container[i].getSize());
}
}
// where you can change the size
all_help_container[0].setSize(50, 50);
System.out.println("----");
for (int i = 0; i < all_help_container.length; i++) {
System.out.println(all_help_container[i].getSize());
}
}
Hopefully this will help you with the sizing of your GUI.
You will have to adjust the different panels to suit your needs. As I'm guessing that this panels will contain some other stuff in them.
You may want to create custom JPanels for each of these, so that you can easily check if they are the right size.
public class VotingPanel extends JPanel {
public VotingPanel(){
//All your variables such as size and color schemes
}
}

Related

JComponents Moving to Origin After Repaint()

Similar to JButton showing up in the wrong spot after repaint is called, but the responses to that question only addressed the fact that he wasn't using a layout manager, while I am using a layout manager (poorly), so it didn't really help, unfortunately.
Details
Intent of the Program:
To show a preview of a 1920x1080 grid (scaled down to 640x480 to save space), stretching and shrinking as you change the height of each square, width of each square, and the number of columns it'll have. (You specify a number of total squares to be in the grid first, so the number of rows is inferred by the program.)
Structure:
One top-level JFrame.
Contains two JPanels: the Grid, and the sidebar, using a BorderLayout to snap them to the east and west sides.
Sidebar is one JPanel containing all of the JComponents in a Y-Axis aligned BoxLayout.
Grid extends JComponent, and uses Graphics.drawLine() to draw the grid.
Each component in the sidebar calls Grid.repaint() when changed to update the grid.
Current UI, with the two main JPanels outlined in red.
The Problem
Whenever I change any of the components and thus call Grid.repaint():
The grid doesn't clear, resulting in multiple lines appearing;
All of the sidebar components get painted at the top-left corner, while still showing/functioning on the sidebar;
The grid resizes itself to be wider than normal for some reason.
Current UI, but borked.
What I've Tried
Changing the repaint() region to be a rectangle that only covers the grid,
Checking the documentation for anything about this,
Google,
Asking you guys.
The Code
Reprex: (Simplified to "Press the button to reproduce", while still keeping the essence of the potential problem areas.)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class BuildGridGUI2
{
static final int WIDTH_MIN = 100;
static final int WIDTH_MAX = 2000;
static final int WIDTH_INIT = 520;
static final int HEIGHT_MIN = 100;
static final int HEIGHT_MAX = 2000;
static final int HEIGHT_INIT = 300;
int widthOfFrames = 255;
int heightOfFrames = 255;
int numCols = 3;
int numFrames = 1;
private final JComponent makeUI()
{
JPanel p = new JPanel();
p.setLayout(new BorderLayout());
Grid g = new Grid();
JComponent j = makeSideMenu(g);
g.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.red),
g.getBorder()));
j.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.red),
j.getBorder()));
p.add(j, BorderLayout.EAST);
p.add(g, BorderLayout.WEST);
return p;
}
private final JComponent makeSideMenu(Grid grid)
{
JPanel p = new JPanel();
JLabel numColsSelectorLabel = new JLabel("Frames Per Column");
JSpinner numColsSelectorField = new JSpinner();
JLabel widthLabel = new JLabel("Width per Frame (Pixels)");
JSpinner widthSpinner = new JSpinner();
JSlider widthSlider = new JSlider(WIDTH_MIN, WIDTH_MAX, WIDTH_INIT);
JLabel heightLabel = new JLabel("Height per Frame (Pixels)");
JSpinner heightSpinner = new JSpinner();
JSlider heightSlider = new JSlider(BuildGridGUI2.HEIGHT_MIN, BuildGridGUI2.HEIGHT_MAX, BuildGridGUI2.HEIGHT_INIT);
JButton confirmButton = new JButton("Confirm");
numColsSelectorField.setEditor(new JSpinner.NumberEditor(numColsSelectorField));
numColsSelectorField.setMaximumSize(numColsSelectorField.getPreferredSize());
widthSlider.setMajorTickSpacing(300);
widthSlider.setMinorTickSpacing(20);
widthSlider.setPaintTicks(true);
widthSlider.setPaintLabels(true);
widthSpinner.setEditor(new JSpinner.NumberEditor(widthSpinner));
widthSpinner.setPreferredSize(new Dimension(70, 30));
widthSpinner.setMaximumSize(widthSpinner.getPreferredSize());
heightSlider.setMajorTickSpacing(300);
heightSlider.setMinorTickSpacing(20);
heightSlider.setPaintTicks(true);
heightSlider.setPaintLabels(true);
heightSpinner.setEditor(new JSpinner.NumberEditor(heightSpinner));
heightSpinner.setPreferredSize(new Dimension(70, 30));
heightSpinner.setMaximumSize(heightSpinner.getPreferredSize());
confirmButton.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e)
{
widthOfFrames = 200;
grid.refresh();
}
});
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
p.setPreferredSize(new Dimension(300, 480));
p.setSize(new Dimension(300, 480));
numColsSelectorLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
numColsSelectorField.setAlignmentX(Component.CENTER_ALIGNMENT);
widthSlider.setAlignmentX(Component.CENTER_ALIGNMENT);
heightSlider.setAlignmentX(Component.CENTER_ALIGNMENT);
confirmButton.setAlignmentX(Component.CENTER_ALIGNMENT);
widthLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
heightLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
widthSpinner.setAlignmentX(Component.CENTER_ALIGNMENT);
heightSpinner.setAlignmentX(Component.CENTER_ALIGNMENT);
p.add(Box.createRigidArea(new Dimension(300, 30)));
p.add(numColsSelectorLabel);
p.add(Box.createRigidArea(new Dimension(300, 5)));
p.add(numColsSelectorField);
p.add(Box.createRigidArea(new Dimension(300, 25)));
p.add(widthLabel);
p.add(Box.createRigidArea(new Dimension(300, 3)));
p.add(widthSpinner);
p.add(widthSlider);
p.add(Box.createRigidArea(new Dimension(300, 25)));
p.add(heightLabel);
p.add(Box.createRigidArea(new Dimension(300, 3)));
p.add(heightSpinner);
p.add(heightSlider);
p.add(Box.createRigidArea(new Dimension(300, 45)));
p.add(confirmButton);
return p;
}
private static void createAndShowGUI() {
BuildGridGUI2 b = new BuildGridGUI2();
JFrame mainFrame = new JFrame("Grid Builder");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setSize(940, 480);
mainFrame.getContentPane().add(b.makeUI());
mainFrame.setResizable(false);
mainFrame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
class Grid extends JComponent
{
static final int CANVAS_WIDTH = 640;
static final int CANVAS_HEIGHT = 480;
private final double conversionRatio = 4.0/9.0; // 1080p scaled down to 480p preview
private int squareHeight, squareWidth, numColumns, numRows;
public Grid()
{
setOpaque(true);
setSize(CANVAS_WIDTH, CANVAS_HEIGHT); // trying to get the size to work properly.
setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
}
#Override
public Dimension getPreferredSize()
{
return new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
updateVars();
int k;
for (k = 0; k < numColumns; k++)
{
// #param: (x1, y1), (x2, y2)
g.drawLine(k * squareWidth, 0, k * squareWidth, CANVAS_HEIGHT);
}
for (k = 0; k < numRows; k++)
{
g.drawLine(0, k * squareHeight, CANVAS_WIDTH, k * squareHeight);
}
}
public void refresh()
{
// Attempting to set the repaint area to only the grid region
// because CTRL+F is free and parameters are not
repaint(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
}
public void updateVars()
{
this.squareWidth = (int)(
(double)BuildGridGUI2.this.widthOfFrames
*
conversionRatio);
this.squareHeight = (int)(
(double)BuildGridGUI2.this.heightOfFrames
*
conversionRatio);
this.numColumns = BuildGridGUI2.this.numCols;
this.numRows = (int)(
(
(double)BuildGridGUI2.this.numFrames
/
numColumns
)
+ 0.5);
}
}
}
Actual Source Code (Not strictly relevant, but if you're in the mood for code review then I'd love to learn better coding conventions.)
Thank you!
All of the sidebar components get painted at the top-left corner, while still showing/functioning on the sidebar;
JComponent is an abstract class that all Swing components extend from. It has no default painting logic.
Therefore invoking super.paintComponent(...) does not really do anything.
In particular it does not clear the background of the component before doing custom painting. This will result in the painting artifacts that you see.
Any time you extend JComponent your logic should be something something like:
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
// clear background
g.setColor( getBackground() );
g.fillRect(0, 0, getWidth(), getHeight());
// do custom painting
g.setColor( getForeground() );
...
}
Note: this is the reason the many people override JPanel for simple custom painting as mentioned by Abra. The paintComponent(...) method of the JPanel will clear the background by default.
I made a few changes to the code you posted.
I changed class Grid such that it extends JPanel and not JComponent, since custom painting is usually done on a JPanel.
I added a instance member variable grid with type Grid, to class BuildGridGUI2 rather than creating one and sending it as a parameter to method makeSideMenu.
Here is your code with my modifications (and my preferred coding style). It simply solves your reported problem and nothing more.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class BuildGridGUI2 {
static final int WIDTH_MIN = 100;
static final int WIDTH_MAX = 2000;
static final int WIDTH_INIT = 520;
static final int HEIGHT_MIN = 100;
static final int HEIGHT_MAX = 2000;
static final int HEIGHT_INIT = 300;
int widthOfFrames = 255;
int heightOfFrames = 255;
int numCols = 3;
int numFrames = 1;
Grid grid;
private final JComponent makeUI() {
JPanel p = new JPanel();
p.setLayout(new BorderLayout());
grid = new Grid();
JComponent j = makeSideMenu();
grid.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.red),
grid.getBorder()));
j.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(Color.red),
j.getBorder()));
p.add(j, BorderLayout.EAST);
p.add(grid, BorderLayout.WEST);
return p;
}
private final JComponent makeSideMenu() {
JPanel p = new JPanel();
JLabel numColsSelectorLabel = new JLabel("Frames Per Column");
JSpinner numColsSelectorField = new JSpinner();
JLabel widthLabel = new JLabel("Width per Frame (Pixels)");
JSpinner widthSpinner = new JSpinner();
JSlider widthSlider = new JSlider(WIDTH_MIN, WIDTH_MAX, WIDTH_INIT);
JLabel heightLabel = new JLabel("Height per Frame (Pixels)");
JSpinner heightSpinner = new JSpinner();
JSlider heightSlider = new JSlider(BuildGridGUI2.HEIGHT_MIN,
BuildGridGUI2.HEIGHT_MAX,
BuildGridGUI2.HEIGHT_INIT);
JButton confirmButton = new JButton("Confirm");
numColsSelectorField.setEditor(new JSpinner.NumberEditor(numColsSelectorField));
numColsSelectorField.setMaximumSize(numColsSelectorField.getPreferredSize());
widthSlider.setMajorTickSpacing(300);
widthSlider.setMinorTickSpacing(20);
widthSlider.setPaintTicks(true);
widthSlider.setPaintLabels(true);
widthSpinner.setEditor(new JSpinner.NumberEditor(widthSpinner));
widthSpinner.setPreferredSize(new Dimension(70, 30));
widthSpinner.setMaximumSize(widthSpinner.getPreferredSize());
heightSlider.setMajorTickSpacing(300);
heightSlider.setMinorTickSpacing(20);
heightSlider.setPaintTicks(true);
heightSlider.setPaintLabels(true);
heightSpinner.setEditor(new JSpinner.NumberEditor(heightSpinner));
heightSpinner.setPreferredSize(new Dimension(70, 30));
heightSpinner.setMaximumSize(heightSpinner.getPreferredSize());
confirmButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
widthOfFrames = 200;
grid.refresh();
}
});
p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
p.setPreferredSize(new Dimension(300, 480));
p.setSize(new Dimension(300, 480));
numColsSelectorLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
numColsSelectorField.setAlignmentX(Component.CENTER_ALIGNMENT);
widthSlider.setAlignmentX(Component.CENTER_ALIGNMENT);
heightSlider.setAlignmentX(Component.CENTER_ALIGNMENT);
confirmButton.setAlignmentX(Component.CENTER_ALIGNMENT);
widthLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
heightLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
widthSpinner.setAlignmentX(Component.CENTER_ALIGNMENT);
heightSpinner.setAlignmentX(Component.CENTER_ALIGNMENT);
p.add(Box.createRigidArea(new Dimension(300, 30)));
p.add(numColsSelectorLabel);
p.add(Box.createRigidArea(new Dimension(300, 5)));
p.add(numColsSelectorField);
p.add(Box.createRigidArea(new Dimension(300, 25)));
p.add(widthLabel);
p.add(Box.createRigidArea(new Dimension(300, 3)));
p.add(widthSpinner);
p.add(widthSlider);
p.add(Box.createRigidArea(new Dimension(300, 25)));
p.add(heightLabel);
p.add(Box.createRigidArea(new Dimension(300, 3)));
p.add(heightSpinner);
p.add(heightSlider);
p.add(Box.createRigidArea(new Dimension(300, 45)));
p.add(confirmButton);
return p;
}
private static void createAndShowGUI() {
BuildGridGUI2 b = new BuildGridGUI2();
JFrame mainFrame = new JFrame("Grid Builder");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setSize(940, 480);
mainFrame.getContentPane().add(b.makeUI());
mainFrame.setResizable(false);
mainFrame.setVisible(true);
}
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
class Grid extends JPanel {
static final int CANVAS_WIDTH = 640;
static final int CANVAS_HEIGHT = 480;
private final double conversionRatio = 4.0 / 9.0; // 1080p scaled down to 480p preview
private int squareHeight, squareWidth, numColumns, numRows;
public Grid() {
setOpaque(true);
setSize(CANVAS_WIDTH, CANVAS_HEIGHT); // trying to get the size to work properly.
setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
updateVars();
int k;
for (k = 0; k < numColumns; k++) {
// #param: (x1, y1), (x2, y2)
g.drawLine(k * squareWidth, 0, k * squareWidth, CANVAS_HEIGHT);
}
for (k = 0; k < numRows; k++) {
g.drawLine(0, k * squareHeight, CANVAS_WIDTH, k * squareHeight);
}
}
public void refresh() {
// Attempting to set the repaint area to only the grid region
// because CTRL+F is free and parameters are not
repaint(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
}
public void updateVars() {
this.squareWidth = (int) ((double) BuildGridGUI2.this.widthOfFrames * conversionRatio);
this.squareHeight = (int) ((double) BuildGridGUI2.this.heightOfFrames * conversionRatio);
this.numColumns = BuildGridGUI2.this.numCols;
this.numRows = (int) (((double) BuildGridGUI2.this.numFrames / numColumns) + 0.5);
}
}
}
One tip: Try to use specific sub-classes of JComponent rather than JComponent. For example, I suggest changing the return type of method makeSideMenu() to JPanel rather than JComponent since that method actually returns a JPanel.

JScrollPane not showing scrollbars when an Array of JPanels are added to it

Im adding an array of JPanels inside a JScrollPane. The array of JPanels are being added to the JScrollPane but the scroll bars just wont show.
public class MyFrame extends JFrame {
private JPanel contentPane;
private JPanel panel_1;
private JScrollPane scrollPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
MyFrame frame = new MyFrame();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public MyFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 288, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
panel_1 = new JPanel();
panel_1.setBounds(10, 114, 434, 136);
panel_1.setLayout(null);
scrollPane = new JScrollPane(panel_1);
scrollPane.setBounds(52, 57, 164, 126);
scrollPane.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Histogram", TitledBorder.LEADING, TitledBorder.TOP, null, Color.BLUE));
scrollPane.setLayout(new ScrollPaneLayout());
contentPane.add(scrollPane);
buildBar();
}
JPanel[] barPanel;
private void buildBar(){
int x=0,y=22,w=100,h=80,s=10,n=3;
barPanel = new JPanel[n];
for(int i=0; i<n; i++){
barPanel[i] = new JPanel();
barPanel[i].setBounds(x, y, w, h);
barPanel[i].setBackground(new Color(255,0,0));
panel_1.add(barPanel[i]);
panel_1.revalidate();
panel_1.repaint();
x = x + w + s;
}
}
}
I have been working on it for hours . Maybe there is something that I've missed out.
You're shooting yourself in the foot with these two lines:
panel_1.setBounds(10, 114, 434, 136);
panel_1.setLayout(null);
Both of which will mess up the JScrollPane's ability to use and display scrollbars. What you need to do is: not to use setBounds but rather have the components use their preferredSize, and avoid using null layout, since this won't change the container's preferredSize.
Yet another reason to studiously avoid null layouts.
e.g.,
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.*;
public class MyPanel2 extends JPanel {
private static final int PREF_W = 388;
private static final int PREF_H = PREF_W;
public static final int INNER_PREF_W = 434;
public static final int INNER_PREF_H = 126;
private static final int HISTO_PANEL_COUNT = 6;
private static final Dimension VP_SZ = new Dimension(164, 126);
private JPanel holderPanel = new JPanel(new GridLayout(0, 1));
public MyPanel2() {
int w = INNER_PREF_W;
int h = INNER_PREF_H;
for (int i = 0; i < HISTO_PANEL_COUNT; i++) {
holderPanel.add(new InnerPanel(w, h));
}
JScrollPane scrollPane = new JScrollPane(holderPanel);
scrollPane.getViewport().setPreferredSize(VP_SZ);
setLayout(new GridBagLayout());
add(scrollPane);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class InnerPanel extends JPanel {
private int w;
private int h;
public InnerPanel(int w, int h) {
this.w = w;
this.h = h;
setBorder(BorderFactory.createLineBorder(Color.BLUE));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = 0, y = 22, w = 100, h = 80, s = 10, n = 3;
g.setColor(Color.RED);
for (int i = 0; i < n; i++) {
g.fillRect(x, y, w, h);
x = x + w + s;
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(w, h);
}
}
private static void createAndShowGui() {
MyPanel2 mainPanel = new MyPanel2();
JFrame frame = new JFrame("MyPanel2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
JScrollPane relies on the preferredSize of your container to determine the scroll bar width. If you use a Layout, the preferredSize will be determined for you when components are added to the panel.
However, when you use:
contentPane.setLayout(null);
You are preventing the preferredSize from changing based on added components.
Try to use a layout which is applicable for your case.
In case you are very certain you do not want to use a Layout, in order to see the scroll bar, you may set the preferredSize of the container for every components you added by manually adjusting the preferredSize. That way, the scrollbar will still extend with newly added components.

Getting text input without swing in Java

Hi I'm making a game in Java that randomly generates 100 numbers, and then
ask the user to memorize as many as then can and then try to recall as many as they can. My game uses a JPanel and a Graphics g object to do all the drawing. How do I "draw" a JTextfield or get one to work on a jpanel?
Add a ActionListener to JTextField and then add that JTextField to JPanel. Now add this JPanel to JFrame using this.add(jpnel, BorderLayout.SOUTH);
Create a new JPanel class Board where you draw things. Add that JPanel to JFrame as, this.add(new Board(), BorderLayout.CENTER);.
Here I coded one example for you. Now you should have an idea how to do that...
Board class
public class Board extends JPanel {
int[] numbers = {3, 25, 5, 6, 60, 100};
int index = 0;
static String num;
boolean once = true;
FontMetrics fm;
Board() {
setPreferredSize(new Dimension(400, 200));
setBackground(Color.decode("#ffde00"));
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
if (index < 6) {
num = numbers[index] + "";
} else {
num = "Game Ended.";
Window.ans.setEditable(false);
}
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setFont(new Font("Arial", Font.PLAIN, 50));
if(once){
fm = g2.getFontMetrics();
once = false;
}
int x = ((getWidth() - fm.stringWidth(num)) / 2);
int y = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
g2.drawString(num + "", x, y);
index++;
}
}
Window class
public class Window extends JFrame {
JPanel p = new JPanel();
JLabel lbl = new JLabel("Enter the number if you have seen it before, Else empty.");
JLabel res = new JLabel("....");
static JTextField ans = new JTextField(10);
Board board = new Board();
public Window() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(board, BorderLayout.CENTER);
p.setLayout(new BorderLayout(8, 8));
p.add(lbl, BorderLayout.WEST);
ans.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (ans.getText().equals(Board.num)) {
res.setText("Good");
} else {
res.setText("Bad");
}
ans.setText("");
board.repaint();
}
});
p.add(ans, BorderLayout.CENTER);
p.add(res, BorderLayout.EAST);
p.setBorder(new EmptyBorder(10, 10, 10, 10));
this.add(p, BorderLayout.SOUTH);
setResizable(false);
pack();
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Window();
}
});
}
}

Java, BorderLayout.CENTER, getting the width and height of the JPanel

I am using Swing and AWT (for the listeners) to make a small program. I have a problem concerning getting the size of my JPanel (the class named Chess).
My Layout:
public class Main extends JFrame implements MouseListener, ActionListener{
Chess chessPanel = new Chess ();
JButton newGameButton = new JButton ("New Game");
JButton loadGameButton = new JButton ("Load Game");
JButton saveGameButton = new JButton ("Save Game");
JButton exitButton = new JButton ("Exit");
public static void main (String [] args) {
new Main();
}
Main () {
super ("Chess");
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
setSize(dim);
setLocation(0,0);
setUndecorated(true);
chessPanel.addMouseListener(this);
add(chessPanel, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout());
newGameButton.addActionListener(this);
loadGameButton.addActionListener(this);
saveGameButton.addActionListener(this);
exitButton.addActionListener(this);
buttonPanel.add(newGameButton);
buttonPanel.add(loadGameButton);
buttonPanel.add(saveGameButton);
buttonPanel.add(exitButton);
add(buttonPanel, BorderLayout.SOUTH);
setVisible(true);
}
// ... Code ...
}
As you can see by the code, I have one JPanel in the CENTER, which takes nearly all the screen. In the bottom I have another JPanel (SOUTH), which has a row of buttons.
What I need is the size that the JPanel in the CENTER takes. When I call the getWidth(), getHeight() or getBounds() methods inherited from JPanel, they all return 0, because of the BorderLayout.
Any idea how to get the real values?
PS: The screen always takes up the entire screen, and will never be resized, if that helps.
You're likely calling getWidth before the JPanel has been rendered, and so it will be 0. The solution is to get the size after rendering, for instance after pack() or setVisible(true) has been called on the root container that holds this JPanel.
Also, I recommend against calling setSize() on anything since most of the standard layout managers observe the preferred size of a component, not the size, and when you call pack() telling the layout managers to do their thing, the set sizes are usually ignored. You may want to make your JPanel that is in the center set its own size by overriding its setPreferredSize method if it needs to be a certain size. Then let the JFrame and its held containers set the bet fit size based on the their layout managers when you call pack.
e.g.,
import java.awt.*;
import javax.swing.*;
public class Main extends JFrame {
Chess chessPanel = new Chess();
JButton newGameButton = new JButton("New Game");
JButton loadGameButton = new JButton("Load Game");
JButton saveGameButton = new JButton("Save Game");
JButton exitButton = new JButton("Exit");
public static void main(String[] args) {
new Main();
}
Main() {
super("Chess");
add(chessPanel, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout());
buttonPanel.add(newGameButton);
buttonPanel.add(loadGameButton);
buttonPanel.add(saveGameButton);
buttonPanel.add(exitButton);
System.out.printf("chessPanel Size before rendering: %s%n", chessPanel.getSize());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(buttonPanel, BorderLayout.SOUTH);
pack();
System.out.printf("chessPanel Size after rendering: %s%n", chessPanel.getSize());
setLocationRelativeTo(null);
setVisible(true);
}
// ... Code ...
}
#SuppressWarnings("serial")
class Chess extends JPanel {
private static final int CHESS_WIDTH = 600;
private static final int CHESS_HEIGHT = CHESS_WIDTH;
private static final int MAX_ROW = 8;
private static final int MAX_COL = 8;
private static final Color LIGHT_COLOR = new Color(240, 190, 40);
private static final Color DARK_COLOR = new Color(180, 50, 0);
#Override
public Dimension getPreferredSize() {
return new Dimension(CHESS_WIDTH, CHESS_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int panelWidth = getWidth();
int panelHeight = getHeight();
int sqrWidth = panelWidth / MAX_ROW;
int sqrHeight = panelHeight / MAX_COL;
for (int row = 0; row < MAX_ROW; row++) {
for (int col = 0; col < MAX_COL; col++) {
Color c = (row % 2 == col % 2) ? LIGHT_COLOR : DARK_COLOR;
g.setColor(c);
int x = (row * panelWidth) / MAX_ROW;
int y = (col * panelHeight) / MAX_COL;
g.fillRect(x, y, sqrWidth, sqrHeight);
}
}
}
}

How to get image's coordinate on JPanel

This question is related to my previous question How to generate Cartesian Coordinate (x,y) from GridBaglayout?
I have successfully get the coordinate of each pictures, however when I checked the coordinate through (System.out.println) and the placement of the images on the screen, it seems to be wrong. e.g. if on the screen it was obvious that the x point of the first picture is on cell 2 which is on coordinate of 20, but the program shows x=1.
Here is part of the code:
public Grid (){
setPreferredSize(new Dimension(600,600));
....
setLayout(new GridBagLayout());
GridBagConstraints gc = new GridBagConstraints();
gc.weightx = 1d;
gc.weighty = 1d;
gc.insets = new Insets(0, 0, 0, 0);//top, left, bottom, and right
gc.fill = GridBagConstraints.BOTH;
JLabel[][] label = new JLabel[ROWS][COLS];
Random rand = new Random();
// fill the panel with labels
for (int i=0;i<IMAGES;i++){
ImageIcon icon = createImageIcon("myPics.jpg");
int r, c;
do{
//pick random cell which is empty
r = (int)Math.floor(Math.random() * ROWS);
c = (int)Math.floor(Math.random() * COLS);
} while (label[r][c]!=null);
//randomly scale the images
int x = rand.nextInt(50)+30;
int y = rand.nextInt(50)+30;
Image image = icon.getImage().getScaledInstance(x,y, Image.SCALE_SMOOTH);
icon.setImage(image);
JLabel lbl = new JLabel(icon); // Instantiate GUI components
gc.gridx = r;
gc.gridy = c;
add(lbl, gc); //add(component, constraintObj);
label[r][c] = lbl;
}
I checked the coordinate through this code:
Component[] components = getComponents();
for (Component component : components) {
System.out.println(component.getBounds());
}
You can use SwingUtilities convertPointToScreen() and convertPointFromScreen() to convert between screen and component coordinates.
Addendum: Here's a simple example I used when trying to understand how components move and resize under the influence of a layout manager.
public class MyPanel extends JPanel {
public MyPanel() {
super(new GridLayout(4, 4));
for (int i = 0; i < 16; i++) {
JPanel panel = new JPanel(new GridLayout());
panel.add(new CenterLabel());
this.add(panel);
}
}
private static void create() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyPanel());
f.pack();
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
create();
}
});
}
private static class CenterLabel extends JLabel {
public CenterLabel() {
this.setHorizontalAlignment(JLabel.CENTER);
this.setVerticalAlignment(JLabel.CENTER);
this.setOpaque(true);
this.setBackground(Color.lightGray);
this.setBorder(BorderFactory.createLineBorder(Color.blue));
this.setPreferredSize(new Dimension(160, 100));
this.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
int w = e.getComponent().getWidth();
int h = e.getComponent().getHeight();
CenterLabel.this.setText("[" + w/2 + "\u253C" + h/2 + "]");
}
});
}
}
}
if on the screen it was obvious that
the x point of the first picture is on
cell 2 which is on coordinate of 20,
but the program shows x=1.
The first image will have x/y coordinates of 0/0. The second images will have coordinates of 1/0. The X/Y values of offset from 0. Is that what you are talking about?
Or is your listener added to the image not the panel in which case you need to convert the image coordinates to the panel coordinates. Check our the SwingUtilities class for methods to do this.
If you need more help post your SSCCE.

Categories