Java buttons on top of graphics in a GUI issue - java

For my end of the year project, I'm trying to make a game which helps a person study different questions, which are shown in a GUI. Ideally, buttons will be available for the user to press and see if their answer was correct. I have made the basis of the GUI with the variables, the ArrayList <String[]> variable which will hold the questions with their answers, and tried to make buttons.
However, when I try to run the program, the buttons (I only have one in the code shown) are cut off and I am unable to place them where they properly belong. Please help!
Somebody please show me a solution that actually has been tested and works! I can't seem to get it based off what has been posted for me so far!
Here's what it looks like when I run it:
And here's all of the program's code:
import java.awt.*;
import javax.swing.*;
import java.awt.geom.Line2D;
import java.util.*;
import java.awt.event.*;
public class EuroGUI extends JPanel {
//Instantiate necessary variables.
ArrayList <String[]> questions = new ArrayList <String[]>(); //Stores (Question + Answers, Correct Answer)
int width = 1280; //GUI Size
int height = 720; // ^
int correct = 0; //Number of correct answers
int attempted = 0; //Number of questions attempted
int streak = 0; //Number of correct answers in a row
int points = 0; //Points accumulated
Font title = new Font("Serif", Font.PLAIN, 60);
Font statsTitle = new Font("Serif", Font.PLAIN, 45);
Font sig = new Font("Mistral", Font.PLAIN, 45);
//Drop down options stuff
JMenu ddMenu = new JMenu("Select an option");
String[] dropDown = new String[] {"A", "B", "C", "D", "E"};
String completion = "starting"; //Determines if the first time repainting
Scanner keyboard = new Scanner(System.in); //Make a keyboard object to test stuff
public static void main(String[]args){ //Main Runner
EuroGUI g = new EuroGUI();
g.setUpScreen();
g.repaint();
}
public void setUpScreen() { //Create the physical GUI, which paints all graphics
//Used http://www.mathcs.emory.edu/~cheung/Courses/377/Syllabus/8-JDBC/GUI/Progs/Layout1.java for buttons
//Create actual GUI window and graphics.
//Create actual GUI window and graphics.
JFrame f = new JFrame("AP European History Study Tool");
JPanel panelGrid = new JPanel();
panelGrid.setLayout(new GridLayout());
setLayout(null);
JPanel panelBorder = new JPanel();
panelBorder.setLayout(new BorderLayout());
JButton xA = new JButton("Choice A");
panelGrid.add(xA, "West");
panelBorder.setLocation(500,500);
f.getContentPane().add(panelBorder);
f.setResizable(false);
f.setVisible(true);
f.setSize(width, height);
f.setBackground(Color.lightGray);
f.add(this);
}
public void paintComponent(Graphics g) { //Draws information on the GUI (Found information on graphics 2D at http://www.tutorialspoint.com/javaexamples/gui_line.htm)
Graphics2D g2 = (Graphics2D) (g);
//Draw a background box which will cover anything that was not re-painted over.
g.setColor(Color.lightGray);
g.fillRect (0, 1280, 0, 720);
//Title "interface"
//Change color back for the lines;
g.setColor(Color.blue);
//Enable bolder lines.
g2.setStroke(new BasicStroke(6));
//Create a box of lines around the title.
g2.draw(new Line2D.Double(200, 0, 200, 120));
g2.draw(new Line2D.Double(200, 120, 1070, 120));
g2.draw(new Line2D.Double(1070, 0, 1070, 120));
g2.draw(new Line2D.Double(200, 0, 1070, 0));
//Fill in box with title with some colors :)
g.setColor(Color.green);
g.fillRect (200, 0, 870, 120);
//Write title
g2.setFont(title);
g.setColor(Color.cyan);
g.drawString("AP European History Study Tool", 240, 80);
g.setColor(Color.black);
g.drawString("AP European History Study Tool", 238, 78);
//Signiature on Title
g.setColor(Color.white);
g2.setFont(sig);
g.drawString("by My Name", 600, 120);
g.setColor(Color.blue);
g.drawString("by My Name", 598, 118);
//Statistics Bar Outline
g.setColor(Color.blue);
g2.draw(new Line2D.Double(1000, 170, 1000, 670));
g2.draw(new Line2D.Double(1000, 170, 1280, 170));
g2.draw(new Line2D.Double(1280, 170, 1280, 670));
g2.draw(new Line2D.Double(1000, 670, 1280, 670));
g2.setStroke(new BasicStroke(6));
g.setColor(Color.black);
g.fillRect (1000, 170, 1280, 500);
g.setColor(Color.green); //Underline
g2.setStroke(new BasicStroke(2));
g2.draw(new Line2D.Double(1055, 230, 1215, 230));
g2.setStroke(new BasicStroke(6));
//Overall Score
g2.setFont(statsTitle);
g2.setColor(Color.green);
g.drawString("Statistics", 1055, 220);
g2.setColor(Color.cyan);
g.drawString(correct + "/" + attempted + " Correct", 1035, 285);
//Streak
if (streak >= 3)
{
g2.setColor(Color.red);
g.drawString(streak + " Streak", 1060, 340);
}
else{
g2.setColor(Color.cyan);
g.drawString(streak + " Streak", 1060, 340);
}
if (completion.equals("starting")){
}
}
}

This is a symptom of breaking the paint chain.
Graphics is a shared resources, that is, the same Graphics context is used to paint all the components within a paint cycle.
One of the jobs of paintComponent is to prepare the Graphics context for painting by clearing it before anything is painted to it.
So instead of...
public void paintComponent(Graphics g) { //Draws information on the GUI (Found information on graphics 2D at http://www.tutorialspoint.com/javaexamples/gui_line.htm)
Graphics2D g2 = (Graphics2D) (g);
Try using
public void paintComponent(Graphics g) { //Draws information on the GUI (Found information on graphics 2D at http://www.tutorialspoint.com/javaexamples/gui_line.htm)
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) (g);
Pixel perfect layouts are an illusion in modern UIs. You don't control factors like font metrics, dpi or rendering pipelines which all effect the amount of space individual components might need. Instead you should make use of appropriate layout managers and consider using compound layouts to produce more complex solutions
Updated with example
There are a number of things wrong, the main problem is, panelGrid isn't been added to anything. The null layout manager is also not helping.
You're also focusing all your efforts into a single panel, which is going to make life messy.
Instead, try separating each section into its own component and focus on there individual needs, you'll find it much easier to manage in the long run.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
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.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.MatteBorder;
public class Example {
public static void main(String[] args) {
new Example();
}
public Example() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new HeaderPane(), BorderLayout.NORTH);
frame.add(new StatisticsPane(), BorderLayout.EAST);
frame.add(new QuestionPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class HeaderPane extends JPanel {
public HeaderPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.SOUTH;
// gbc.ipadx = 100;
NamePane namePane = new NamePane();
FontMetrics fm = namePane.getFontMetrics(namePane.getFont());
add(namePane, gbc);
gbc.insets = new Insets(0, 0, fm.getDescent(), 0);
gbc.gridx = 0;
gbc.gridwidth = 2;
gbc.ipadx = 10;
gbc.ipady = 10;
gbc.anchor = GridBagConstraints.CENTER;
add(new TitlePane(), gbc);
}
public class ShadowLabel extends JPanel {
private String text;
private Color shadowColor;
private int shadowOffset;
public ShadowLabel(String text, Color shadowColor) {
this.text = text;
this.shadowColor = shadowColor;
this.shadowOffset = 2;
}
public int getShadowOffset() {
return shadowOffset;
}
public void setShadowOffset(int shadowOffset) {
this.shadowOffset = shadowOffset;
}
#Override
public Dimension getPreferredSize() {
FontMetrics fm = getFontMetrics(getFont());
return new Dimension(fm.stringWidth(getText()), fm.getHeight());
}
public String getText() {
return text;
}
public Color getShadowColor() {
return shadowColor;
}
public void setText(String text) {
this.text = text;
repaint();
}
public void setShadowColor(Color shadowColor) {
this.shadowColor = shadowColor;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setFont(getFont());
FontMetrics fm = g.getFontMetrics();
int x = (getWidth() - fm.stringWidth(getText())) / 2;
int y = (getHeight() - fm.getHeight()) / 2;
g.setColor(getShadowColor());
g.drawString(getText(), x + getShadowOffset(), y + getShadowOffset() + fm.getAscent());
g.setColor(getForeground());
g.drawString(getText(), x, y + fm.getAscent());
}
}
public class TitlePane extends ShadowLabel {
public TitlePane() {
super("AP European History Study Tool", Color.CYAN);
setBackground(Color.GREEN);
setBorder(new MatteBorder(0, 1, 1, 1, Color.BLUE));
setFont(new Font("Serif", Font.PLAIN, 60));
}
}
public class NamePane extends ShadowLabel {
public NamePane() {
super("by Me", Color.WHITE);
setForeground(Color.BLUE);
setFont(new Font("Mistral", Font.PLAIN, 45));
setOpaque(false);
}
}
}
public class StatisticsPane extends JPanel {
private JLabel score;
private JLabel streak;
public StatisticsPane() {
setLayout(new BorderLayout());
setBackground(Color.BLACK);
setBorder(new CompoundBorder(new LineBorder(Color.BLUE), new EmptyBorder(4, 4, 4, 4)));
JLabel statistics = new JLabel("Statistics");
statistics.setFont(new Font("Serif", Font.PLAIN, 45));
statistics.setForeground(Color.GREEN);
statistics.setBorder(new CompoundBorder(new MatteBorder(0, 0, 1, 0, Color.GREEN), new EmptyBorder(4, 4, 4, 4)));
add(statistics, BorderLayout.NORTH);
score = new JLabel("0/0 correct");
score.setForeground(Color.GREEN);
score.setFont(new Font("Serif", Font.PLAIN, 45));
streak = new JLabel("0 streak");
streak.setForeground(Color.GREEN);
streak.setFont(new Font("Serif", Font.PLAIN, 45));
JPanel pnl = new JPanel(new GridBagLayout());
pnl.setOpaque(false);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
pnl.add(score, gbc);
gbc.gridy++;
gbc.weighty = 1;
gbc.anchor = GridBagConstraints.NORTH;
pnl.add(streak, gbc);
add(pnl);
}
}
public class QuestionPane extends JPanel {
public QuestionPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.WEST;
JButton xA = new JButton("Choice A");
add(xA, gbc);
}
}
}
I would also separate the management of the data and the UI, so that the data is managed by some kind of model or models which can respond to changes in the UI and visa-versa. This means that your UI becomes a visual representation of your data model and allows the two to decouple and work independently from each other...
Take a look Model–view–controller for more details. Note: Swing uses a version of this, but it's more like Model-View and Controller
You should also take a look at Creating a GUI With JFC/Swing to see how you make better use of the ready made components available in Swing

You did not set up your Layout properly. Might not be exactly what you are looking for but if you change from a FlowLayout to a BorderLayout it seems to fix your issue. Also you don't use panel2 anywhere in you code so you can remove it.
public void setUpScreen() { //Create the physical GUI, which paints all graphics
//Used http://www.mathcs.emory.edu/~cheung/Courses/377/Syllabus/8-JDBC/GUI/Progs/Layout1.java for buttons
//Create actual GUI window and graphics.
JFrame f = new JFrame("AP European History Study Tool");
JPanel panelGrid = new JPanel();
panelGrid.setLayout(new GridLayout());
setLayout(null);
JPanel panelBorder = new JPanel();
panelBorder.setLayout(new BorderLayout());
JButton xA = new JButton("Choice A");
panelGrid.add(xA, "West");
panelBorder.setLocation(500,500);
f.getContentPane().add(panelBorder);
f.setResizable(false);
f.setVisible(true);
f.setSize(width, height);
f.setBackground(Color.lightGray);
f.add(this);
}

Related

JPanel does not appear in JDialog

I am solving an activity with the following statement: Create an application to display in a JDialog window eight JPanel components. Each panel should be colored in one of the eight colors in figure 1.
Figure 1
On each panel should be written the word that translates the meaning of the color. Use font size 18. Each panel should be colored using a color from Table 1, specifying the amount of each RGB (Red, Green, Blue) component that corresponds to the meaning of the color. Use the java.awt.Color class. Should be implementing just a single paintComponent method to paint the 8 panels and write the meaning of each color.
Table 1
The problem is that my JPanel does not appear in JDialog. And I have no idea how to make it appear.
Follows the code:
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class SigCoresGUI extends JDialog {
private static final long serialVersionUID = 1L;
private Color[] cores = { new Color(255, 255, 255), new Color(249, 206, 137), new Color(255, 128, 0),
new Color(255, 0, 0), new Color(244, 102, 174), new Color(5, 120, 203), new Color(116, 186, 160),
new Color(0, 0, 0) };
private String[] sig = { "Paz", "Energia", "Criatividade", "Paixão", "Ternura", "Tranquilidade", "Harmonia",
"Elegância" };
private Font font = new Font("Arial", Font.BOLD, 18);
public SigCoresGUI() {
super();
Desenha desenha = new Desenha();
add(desenha);
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setLocationByPlatform(true);
setLayout(new GridLayout(8, 8));
setSize(400, 500);
setVisible(true);
}
public class Desenha extends JPanel {
private static final long serialVersionUID = 1L;
#Override
public void paintComponents(Graphics g) {
super.paintComponents(g);
for (int i = 0; i < 8; i++) {
JPanel panel = new JPanel();
panel.setBackground(cores[i]);
panel.setFont(font);
JLabel label = new JLabel(sig[i]);
label.setFont(font);
if (i > 0)
label.setForeground(Color.WHITE);
panel.add(label);
add(panel);
}
}
}
}
Never add or remove components from a container (here your JPanel) within a painting method. Painting methods should be for painting and painting only, not for changing the component structure of a container. Understand that you do not have direct control over when or even if a painting method is called, and it can be called many times -- adding many unnecessary components to the container -- and you also never want to slow painting down.
You are overriding paintComponents, a method that (per the API)
Paints each of the components in this container
and since the JPanel has no components to begin with, the method is likely never called.
Instead, add your components in the SigCoresGUI constructor.
Also:
Avoid using setSize(...)
Instead pack() the JDialog before displaying it to let the components and containers size themselves using their preferred sizes.
So this will work although I don't know what layout you're looking for:
import java.awt.*;
import javax.swing.*;
public class SigCoresGUI extends JDialog {
private static final long serialVersionUID = 1L;
private Color[] cores = { new Color(255, 255, 255), new Color(249, 206, 137), new Color(255, 128, 0),
new Color(255, 0, 0), new Color(244, 102, 174), new Color(5, 120, 203), new Color(116, 186, 160),
new Color(0, 0, 0) };
private String[] sig = { "Paz", "Energia", "Criatividade", "Paixão", "Ternura", "Tranquilidade", "Harmonia",
"Elegância" };
private Font font = new Font("Arial", Font.BOLD, 18);
public SigCoresGUI() {
super();
Desenha desenha = new Desenha();
add(desenha);
pack();
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setLocationByPlatform(true);
// setLayout(new GridLayout(8, 8));
// setSize(400, 500);
setVisible(true);
}
public class Desenha extends JPanel {
private static final long serialVersionUID = 1L;
public Desenha() {
setLayout(new GridLayout(0, 1));
for (int i = 0; i < 8; i++) {
JPanel panel = new JPanel(new GridBagLayout());
panel.setBackground(cores[i]);
panel.setFont(font);
panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
JLabel label = new JLabel(sig[i]);
label.setFont(font);
if (i > 0)
label.setForeground(Color.WHITE);
panel.add(label);
add(panel);
}
}
//#Override
//public void paintComponents(Graphics g) {
// super.paintComponents(g);
//}
}
public static void main(String[] args) {
new SigCoresGUI();
}
}

Java Rendering Artifacts When Adding Buttons To Semi-Transparent JPanel

I have a problem. I am trying to create "alert" component that I can display in a JFrame. This alert has a semi-transparent background (70% opacity, white) with any trivial amount of JButtons on it. The background itself has rounded corners, and thus I made a custom component.
When rendering this alert, artifacts appear: no alert-background is rendered on the button that is initially selected. When moving my mouse across the buttons, it looks like the text of the buttons is being drawn in two places for no reason.
Screenshots of the artifacts (top = initial render, bottom = moving mouse around):
Code that causes these problems:
public class Test {
public static void main(String[] args) {
MyRoundedTransparentBackground background = new MyRoundedTransparentBackground();
background.setSize(200, 200);
background.setLocation(100, 100);
background.setLayout(new GridBagLayout());
JPanel spacer = new JPanel();
spacer.setBackground(new Color(0, 0, 0, 0));
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = 1;
c.gridheight = 1;
c.weighty = 1;
background.add(spacer, c);
JButton button1 = new JButton("Hi there");
JButton button2 = new JButton("Bye ...");
button1.setBackground(new Color(0, 0, 0, 0));
button1.setFocusPainted(false);
button1.setBorderPainted(false);
button2.setBackground(new Color(0, 0, 0, 0));
button2.setFocusPainted(false);
button2.setBorderPainted(false);
c.weighty = 0;
c.gridy = 1;
background.add(button1, c);
c.gridx = 1;
background.add(button2, c);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
frame.setLocation(2000, 100);
frame.setLayout(null);
frame.getContentPane().setBackground(Color.red);
frame.add(background);
frame.setVisible(true);
}
private static class MyRoundedTransparentBackground extends JComponent {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(new Color(1f, 1f, 1f, 0.7f));
g2.fillRoundRect(0, 0, getWidth() - 1, getHeight() - 1, 15, 15);
}
}
Can someone help me find out what the issue is, and give a potential solution to achieve the desired behavior?

repaint() function - JAVA Swing

I have a problem when i'm trying to use a Timer Object and a repaint() when it is called.
Here's my Window Class :
import javax.swing.*;
import java.awt.*;
public class Window extends JFrame{
Panel pan = new Panel();
JPanel container, north,south, west;
JButton ip,print,cancel,ok;
JTextArea timeStep;
JLabel legend;
double temperature=0.0;
public static void main(String[] args) {
new Window();
}
public Window()
{
System.out.println("je suis là");
this.setSize(700,400);
this.setLocationRelativeTo(null);
this.setResizable(false);
this.setTitle("Assignment2 - CPU temperature");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
container = new JPanel(new BorderLayout());
north = new JPanel();
ip = new JButton ("New");
north.add(ip);
north.add(new JLabel("Time Step: "));
timeStep = new JTextArea("10",1,5);
north.add(timeStep);
print = new JButton ("Print");
north.add(print);
south = new JPanel();
legend = new JLabel("Legends are here");
south.add(legend);
west = new JPanel();
JLabel temp = new JLabel("°C");
west.add(temp);
container.add(north, BorderLayout.NORTH);
container.add(west,BorderLayout.WEST);
container.add(pan, BorderLayout.CENTER);
container.add(south, BorderLayout.SOUTH);
this.setContentPane(container);
this.setVisible(true);
}
}
And Here's my Panel class :
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class Panel extends JPanel implements ActionListener {
Timer chrono = new Timer(1000,this);
int i = 0;
int t = 10;
public Panel()
{
super();
chrono.start();
}
public void paintComponent(Graphics g)
{
g.drawLine(20, 20, 20, this.getHeight()-50);
g.drawLine(20, this.getHeight()-50, this.getWidth()-50, this.getHeight()-50);
g.drawLine(20, 20, 15, 35);
g.drawLine(20, 20, 25, 35);
g.drawLine(this.getWidth()-50, this.getHeight()-50, this.getWidth()-65, this.getHeight()-45);
g.drawLine(this.getWidth()-50, this.getHeight()-50, this.getWidth()-65, this.getHeight()-55);
g.drawLine(20+t, this.getHeight()-50-i, 20+t, this.getHeight()-50);
}
#Override
public void actionPerformed(ActionEvent e) {
/*i = (int)(50+(20 + (Math.random() * (60 - 20))));
t = t+10;
repaint();
System.out.println("chrono");*/
}
}
Here's how it is like when the repaint() function isn't called :
GUI:
And Finally here's how it looks like when repaint() function is called :
GUI bug:
It seems that all of my JPanels are repainting only once and then everything works...
Any thought?
The problem is that you never paint over what's drawn before. JPanel by default is supposed to be opaque, meaning that it will draw over its entire area each redraw, freeing the frame to not have to worry about cleaning up that space. However, you're removing that functionality from the JPanel.
In your paintComponent method, add this at the top:
super.paintComponent(g);
This will let the JPanel correctly redraw itself (by calling its own paintComponent method), so that you can do your drawing over a clean slate.
In response to your comment, the best way to keep the old lines is to keep track of each line to draw, and repaint them all each time. To do that, you would need to replace t and i with lists, which would look something like this:
List<Integer> is = new ArrayList<>();
List<Integer> ts = new ArrayList<>();
int lastT = 0;
And then add to those instead of simply setting the value:
int i = (int)(50 + (20 + (Math.random() * (60 - 20))));
lastT += 10;
is.add(i);
ts.add(lastT);
repaint();
And finally, loop over each value:
for(int j = 0; i < is.size() && ts.size(); i++){
int i = is.get(j);
int t = ts.get(j);
g.drawLine(20 + t, this.getHeight() - 50 - i,
20 + t, this.getHeight() - 50);
}
I haven't tested the above code, so it may have some mistakes, but it should be the right idea.

Java JLabel Height with multiple lines

Hi I've got a problem in the code below ( in method "append(String str)" mostly). I want to show messages received in HTML format (so I need to use JLabel).
Without setting tac.preferredSize here is what I get:
BUT it isn't working using long string without blank spaces:
such as "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".
If I set tac.preferredSize the height of the bubble isn't increasing:
How can I overcome these problems? (working on layout/sizes and not modifying input string)
Here's the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ClientGUI extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private JLabel label;
private JTextField tf;
private JPanel chatPanel;
private JScrollPane scroll;
ClientGUI() {
super("Chat Client");
label = new JLabel("You can write messages below:", SwingConstants.CENTER);
chatPanel = new JPanel();
tf = new JTextField("");
tf.setBackground(Color.WHITE);
tf.requestFocus();
tf.setVisible(true);
tf.addActionListener(this);
chatPanel.setLayout(new BoxLayout(chatPanel, BoxLayout.PAGE_AXIS));
chatPanel.add(Box.createVerticalGlue());
JPanel centerPanel = new JPanel(new GridLayout(1,1));
scroll = new JScrollPane();
scroll.setViewportView(chatPanel);
scroll.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
centerPanel.add(scroll);
add(centerPanel, BorderLayout.CENTER);
JPanel southPanel = new JPanel(new BorderLayout());
JPanel writeChatPanel = new JPanel(new GridLayout(2,1));
writeChatPanel.add(label);
writeChatPanel.add(tf);
southPanel.add(writeChatPanel, BorderLayout.NORTH);
add(southPanel, BorderLayout.SOUTH);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(600, 600);
setVisible(true);
chatPanel.scrollRectToVisible(new Rectangle(chatPanel.getSize()));
}
void append(String str) {
LeftArrowBubble leftArrowBubble = new LeftArrowBubble();
leftArrowBubble.setMaximumSize(new Dimension(400,350));
JLabel tac = new JLabel();
tac.setMaximumSize(new Dimension(350,400));
//tac.setPreferredSize(new Dimension(350,50)); //<----------
System.out.println(str);
tac.setText("<html><body style='width: 350px; padding:15px;display:block;'>"+str+"</body></html>");
tac.setOpaque(false);
leftArrowBubble.add(tac, BorderLayout.NORTH);
chatPanel.add(leftArrowBubble);
chatPanel.add(Box.createRigidArea(new Dimension(0,5)));
Rectangle rect = chatPanel.getBounds();
Rectangle r2 = scroll.getViewport().getVisibleRect();
chatPanel.scrollRectToVisible(new Rectangle((int) rect.getWidth(),
(int) rect.getHeight(), (int) r2.getWidth(), (int) r2.getHeight()));
revalidate();
repaint();
}
public void actionPerformed(ActionEvent e) {
// just have to send the message
append(tf.getText());
tf.setText("");
return;
}
public static void main(String[] args) {
new ClientGUI();
}
}
And the bubble class:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.GeneralPath;
import javax.swing.BoxLayout;
import javax.swing.JPanel;
public class LeftArrowBubble extends JPanel {
private static final long serialVersionUID = -5389178141802153305L;
public LeftArrowBubble() {
this.setLayout(new BoxLayout(this,BoxLayout.PAGE_AXIS));
}
#Override
protected void paintComponent(final Graphics g) {
final Graphics2D graphics2D = (Graphics2D) g;
RenderingHints qualityHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
qualityHints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics2D.setRenderingHints(qualityHints);
graphics2D.setPaint(new Color(80, 150, 180));
int width = getWidth();
int height = getHeight();
GeneralPath path = new GeneralPath();
path.moveTo(5, 10);
path.curveTo(5, 10, 7, 5, 0, 0);
path.curveTo(0, 0, 12, 0, 12, 5);
path.curveTo(12, 5, 12, 0, 20, 0);
path.lineTo(width - 10, 0);
path.curveTo(width - 10, 0, width, 0, width, 10);
path.lineTo(width, height - 10);
path.curveTo(width, height - 10, width, height, width - 10, height);
path.lineTo(15, height);
path.curveTo(15, height, 5, height, 5, height - 10);
path.lineTo(5, 15);
path.closePath();
graphics2D.fill(path);
}
}
If you break up the words that are too long by adding spaces, I think most of your problems are solved. Some small changes to the dimensions of the leftArrowBubble and tac components would be useful as well.
You could replace the following lines in the append method:
leftArrowBubble.setMaximumSize(new Dimension(400,350));
JLabel tac = new JLabel();
tac.setMaximumSize(new Dimension(350,400));
//tac.setPreferredSize(new Dimension(350,50)); //<----------
System.out.println(str);
tac.setText("<html><body style='width:350px;padding:15px;display:block;'>"
+ str + "</body></html>");
by the following code (you can also take a look at Split string to equal length substrings in Java for more ways to split a string in equal parts):
leftArrowBubble.setMaximumSize(new Dimension(500, 500));
JLabel tac = new JLabel();
tac.setMaximumSize(new Dimension(450, 450));
//tac.setPreferredSize(new Dimension(350, 50)); //<----------
final int maximumSize = 56;
String textWithSeparators = "";
final StringTokenizer textTokenizer
= new StringTokenizer(str, " \t\n\r", true);
while (textTokenizer.hasMoreTokens()) {
final String part = textTokenizer.nextToken();
for (int beginIndex = 0; beginIndex < part.length();
beginIndex += maximumSize)
textWithSeparators += (beginIndex == 0 ? "" : " ")
+ part.substring(beginIndex,
Math.min(part.length(),
beginIndex + maximumSize));
}
System.out.println(textWithSeparators);
tac.setText("<html><body style='width:350px;padding:15px;display:block;'>"
+ textWithSeparators + "</body></html>");
The value for maximumSize could be calculated using font metrics (see How to get the correct String width from FontMetrics in JAVA for more information), but I've used a fixed value here for the sake of simplicity.
It would be nice to link the dimensions of leftArrowBubble, tac, and the width in the html string, like:
final int size = 500;
leftArrowBubble.setMaximumSize(new Dimension(size, size));
JLabel tac = new JLabel();
tac.setMaximumSize(new Dimension(size - 50, size - 50));
// [...]
tac.setText("<html><body style='width:" + (size - 150)
+ "px;padding:15px;display:block;'>"
+ textWithSeparators + "</body></html>");

Cleaning up a Nested J panel

Rebuilt the SCCE for you guys.
My goal is this
The general idea is that clicking on the title bars of the menus (right side) will collapsible (set visible to false) the content panes associated with them:
gender_panel_BG collapses gender_panel_body
race_panel_BG collapses race_panel_body
class_panel_BG collapses class_panel_body
base_stats_panel_BG collapses base_stats_panel_body
merits_panel_BG collapses merits_panel_body
You get the idea
Another thing that is bugging me is the huge space at the top of the body and it's content.
Gradient bar img source
background source source
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import java.awt.*;
import javax.swing.*;
import javax.swing.text.*;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.*;
public class JaGCharCreation {
//set inital size of window
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int initalWidth = (int) screenSize.width - 50;
int initalHeight = (int) screenSize.height - 50;
JPanel gender_panel_body;
GridBagConstraints gbc;
JLabel viewdata_gender = new JLabel("gender");
ImageIcon BGicon = new ImageIcon("parchmentTall.jpg");
Image img1 = BGicon.getImage();
public static void main(String[] args) {
new JaGCharCreation ();
}
//set up thread safe invoking for GUI
public JaGCharCreation () {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
//frame.setLocationRelativeTo(null);
frame.setVisible(true);
// Give the frame an initial size.
frame.setSize(initalWidth, initalHeight);
}
});
}
//main panel to hold all others
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridLayout(0, 2));
add(createLeftPane());
add(createRightPane());
}//end of class for master frame
/////////////////////////////////Left Panel Nest Begin//////////////////////////////////////////////////////////////
protected JPanel createLeftPane() {
img1 = img1.getScaledInstance(initalWidth/2, initalHeight, java.awt.Image.SCALE_SMOOTH);
final ImageIcon BGiconSM = new ImageIcon(img1);
JPanel panel = new JPanel(new BorderLayout()) {
protected void paintComponent(Graphics g)
{
// Dispaly image at full size
g.drawImage(BGiconSM.getImage(), 0, 0, null);
super.paintComponent(g);
}
};
panel.setOpaque( false );
panel.setBorder(new EmptyBorder(35, 80, 35, 80));
//panel.setBackground(Color.RED);
return panel;
}//end left pane
/////////////////////////////////Left Panel Nest End//////////////////////////////////////////////////////////////
/////////////////////////////////Right Panel Nest Begin//////////////////////////////////////////////////////////////
protected JPanel createRightPane() {
img1 = img1.getScaledInstance(initalWidth/2, initalHeight, java.awt.Image.SCALE_SMOOTH);
final ImageIcon BGiconSM = new ImageIcon(img1);
JPanel content = new JPanel(new GridBagLayout());
content.setOpaque(false);
JPanel panel = new JPanel(new BorderLayout()) {
protected void paintComponent(Graphics g)
{
// Dispaly image at full size
g.drawImage(BGiconSM.getImage(), 0, 0, null);
super.paintComponent(g);
}
};
panel.setOpaque( false );
panel.setBorder(new EmptyBorder(35, 80, 35, 80));
//panel.setBackground(Color.BLUE);
//set up our image for the title bars
ImageIcon icon = new ImageIcon("GradientDetail.png");
Image img = icon.getImage();
img = img.getScaledInstance(initalWidth/2, 40, java.awt.Image.SCALE_SMOOTH);
final ImageIcon iconSM = new ImageIcon(img);
/////////////////////////////////Gender Panel Nest Begins//////////////////////////////////////////////////////////////
JPanel gender_panel_BG = new JPanel(new BorderLayout())
{
protected void paintComponent(Graphics g)
{
// Dispaly image at full size
g.drawImage(iconSM.getImage(), 0, 0, null);
super.paintComponent(g);
}
};
gender_panel_BG.setOpaque( false );
JLabel gender_panel_label = new JLabel("Gender");
gender_panel_label.setFont(new Font("Impact", Font.BOLD, 30));
gender_panel_label.setForeground(Color.white);
gender_panel_label.setOpaque(false);
gender_panel_body = new JPanel(new GridLayout(1, 3));
gender_panel_body.setBackground(Color.WHITE);
gender_panel_BG.add(gender_panel_label, BorderLayout.NORTH);
JPanel gender_panel = new JPanel(new GridLayout(2, 1));
//gender_panel.setBorder(new EmptyBorder(0, 10, 0, 10));
//gender_panel.setBackground(Color.GREEN);
gender_panel.setOpaque(false);
gender_panel.add(gender_panel_BG);
gender_panel.add(gender_panel_body);
MouseAdapter gender = new MouseAdapterMod(){
public void mousePressed(MouseEvent e) {
//System.out.println(e.getSource());
System.out.println("A mouse was pressed");
gender_panel_body.setVisible(!gender_panel_body.isVisible());
}//end of mousePressed(MouseEvent e)
};
// Create radio buttons and add them to content pane.
JRadioButton g1 = new JRadioButton("Male");
g1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
viewdata_gender.setText("Gender: Male");
}//action perfomed;
});//g1 add action listener
gender_panel_body.add(g1);
JRadioButton g2 = new JRadioButton("Female");
g2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
viewdata_gender.setText("Gender: Female");
}//action perfomed;
});//g2 add action listener
gender_panel_body.add(g2);
JRadioButton g3 = new JRadioButton("<Unknown>");
g3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
viewdata_gender.setText("Gender: <Unknown>");
}//action perfomed;
});//g3 add action listener
gender_panel_body.add(g3);
// Define a button group.
ButtonGroup genderButtons = new ButtonGroup();
genderButtons.add(g1);
genderButtons.add(g2);
genderButtons.add(g3);
gender_panel_BG.addMouseListener(gender);
content.add(gender_panel, gbc);
/////////////////////////////////Gender Panel Nest End//////////////////////////////////////////////////////////////
/////////////////////////////////Race Panel Nest Begins//////////////////////////////////////////////////////////////
JPanel race_panel_BG = new JPanel(new BorderLayout())
{
protected void paintComponent(Graphics g)
{
// Dispaly image at full size
g.drawImage(iconSM.getImage(), 0, 0, null);
super.paintComponent(g);
}
};
race_panel_BG.setOpaque( false );
JLabel race_panel_label = new JLabel("Race");
race_panel_label.setFont(new Font("Impact", Font.BOLD, 30));
race_panel_label.setForeground(Color.white);
race_panel_label.setOpaque(false);
JPanel race_panel_body = new JPanel(new GridLayout(5, 8));
race_panel_body.setBackground(Color.WHITE);
race_panel_BG.add(race_panel_label, BorderLayout.NORTH);
JPanel race_panel = new JPanel(new GridLayout(2, 1));
//race_panel.setBorder(new EmptyBorder(0, 10, 0, 10));
//race_panel.setBackground(Color.GREEN);
race_panel.setOpaque(false);
race_panel.add(race_panel_BG);
race_panel.add(race_panel_body);
for (int i=0; i <= 60; i++){
ImageIcon RCicon = new ImageIcon("headshot.jpg");
Image RCimg = RCicon.getImage();
RCimg = RCimg.getScaledInstance(40, 40, java.awt.Image.SCALE_SMOOTH);
final ImageIcon RCiconSM = new ImageIcon(RCimg);
JButton button = new JButton(RCiconSM);
button.setBorder(BorderFactory.createEmptyBorder());
button.setContentAreaFilled(false);
race_panel_body.add(button);
};//for loop
MouseAdapter race = new MouseAdapterMod();
race_panel_body.addMouseListener(race);
content.add(race_panel, gbc);
/////////////////////////////////Race Panel Nest End//////////////////////////////////////////////////////////////
/////////////////////////////////Class Panel Nest Begins//////////////////////////////////////////////////////////////
JPanel class_panel_BG = new JPanel(new BorderLayout())
{
protected void paintComponent(Graphics g)
{
// Dispaly image at full size
g.drawImage(iconSM.getImage(), 0, 0, null);
super.paintComponent(g);
}
};
class_panel_BG.setOpaque( false );
JLabel class_panel_label = new JLabel("Class");
class_panel_label.setFont(new Font("Impact", Font.BOLD, 30));
class_panel_label.setForeground(Color.white);
class_panel_label.setOpaque(false);
JPanel class_panel_body = new JPanel(new GridLayout(5, 8));
class_panel_body.setBackground(Color.WHITE);
class_panel_BG.add(class_panel_label, BorderLayout.NORTH);
JPanel class_panel = new JPanel(new GridLayout(2, 1));
//class_panel.setBorder(new EmptyBorder(0, 10, 0, 10));
//class_panel.setBackground(Color.GREEN);
class_panel.setOpaque(false);
class_panel.add(class_panel_BG);
class_panel.add(class_panel_body);
for (int g=0; g <= 50; g++){
ImageIcon CCicon = new ImageIcon("headshot.jpg");
Image CCimg = CCicon.getImage();
CCimg = CCimg.getScaledInstance(40, 40, java.awt.Image.SCALE_SMOOTH);
final ImageIcon CCiconSM = new ImageIcon(CCimg);
JButton cbutton = new JButton(CCiconSM);
cbutton.setBorder(BorderFactory.createEmptyBorder());
cbutton.setContentAreaFilled(false);
class_panel_body.add(cbutton);
};//for loop
MouseAdapter cclass = new MouseAdapterMod();
class_panel_body.addMouseListener(cclass);
content.add(class_panel, gbc);
/////////////////////////////////Class Panel Nest End//////////////////////////////////////////////////////////////
/////////////////////////////////Base Stats Panel Nest Begins//////////////////////////////////////////////////////////////
JPanel base_stats_panel_BG = new JPanel(new BorderLayout())
{
protected void paintComponent(Graphics g)
{
// Dispaly image at full size
g.drawImage(iconSM.getImage(), 0, 0, null);
super.paintComponent(g);
}
};
base_stats_panel_BG.setOpaque( false );
JLabel base_stats_panel_label = new JLabel("Base Attributes");
base_stats_panel_label.setFont(new Font("Impact", Font.BOLD, 30));
base_stats_panel_label.setForeground(Color.white);
base_stats_panel_label.setOpaque(false);
JPanel base_stats_panel_body = new JPanel(new GridLayout(1, 2));
base_stats_panel_body.setBackground(Color.WHITE);
base_stats_panel_BG.add(base_stats_panel_label, BorderLayout.NORTH);
JPanel base_stats_panel = new JPanel(new GridLayout(2, 1));
//base_stats_panel.setBorder(new EmptyBorder(0, 10, 0, 10));
//base_stats_panel.setBackground(Color.GREEN);
base_stats_panel.setOpaque(false);
base_stats_panel.add(base_stats_panel_BG);
base_stats_panel.add(base_stats_panel_body);
MouseAdapter base_stats = new MouseAdapterMod();
base_stats_panel_body.addMouseListener(base_stats);
content.add(base_stats_panel, gbc);
/////////////////////////////////Base Stats Panel Nest End//////////////////////////////////////////////////////////////
/////////////////////////////////Merits Panel Nest Begins//////////////////////////////////////////////////////////////
JPanel merits_panel_BG = new JPanel(new BorderLayout())
{
protected void paintComponent(Graphics g)
{
// Dispaly image at full size
g.drawImage(iconSM.getImage(), 0, 0, null);
super.paintComponent(g);
}
};
merits_panel_BG.setOpaque( false );
JLabel merits_panel_label = new JLabel("Advantages and Disadvantages");
merits_panel_label.setFont(new Font("Impact", Font.BOLD, 30));
merits_panel_label.setForeground(Color.white);
merits_panel_label.setOpaque(false);
JPanel merits_panel_body = new JPanel(new BorderLayout());
merits_panel_body.setBackground(Color.WHITE);
merits_panel_BG.add(merits_panel_label, BorderLayout.NORTH);
JPanel merits_panel = new JPanel(new GridLayout(2, 1));
//merits_panel.setBorder(new EmptyBorder(0, 10, 0, 10));
//merits_panel.setBackground(Color.GREEN);
merits_panel.setOpaque(false);
merits_panel.add(merits_panel_BG);
merits_panel.add(merits_panel_body);
MouseAdapter merits = new MouseAdapterMod();
merits_panel_body.addMouseListener(merits);
content.add(merits_panel, gbc);
/////////////////////////////////Merits Panel Nest End//////////////////////////////////////////////////////////////
/////////////////////////////////Group Panel Nest Begin//////////////////////////////////////////////////////////////
JPanel viewData = new JPanel(new GridLayout(5, 1));
viewData.add(gender_panel);
viewData.add(race_panel);
viewData.add(class_panel);
viewData.add(base_stats_panel);
viewData.add(merits_panel);
panel.add(new JScrollPane(viewData));
return panel;
/////////////////////////////////Group Panel Nest End//////////////////////////////////////////////////////////////
}//end right pane
/////////////////////////////////Right Panel Nest End//////////////////////////////////////////////////////////////
public class MouseAdapterMod extends MouseAdapter {
// usually better off with mousePressed rather than clicked
public void mousePressed(MouseEvent e) {
//System.out.println(e.getSource());
System.out.println("A mouse was pressed");
if (e.getSource() == "gender_panel_BG"){
gender_panel_body.setVisible(!gender_panel_body.isVisible());
}//end of if (e.getSource() == "gender")
}//end of mousePressed(MouseEvent e)
}//end of MouseAdapterMod extends MouseAdapter
}//end master panel set
}//end master class
Now I need to figure out how to select multiple JButtons. It's not quite a check box, as I want to have images instead of tick boxes.
JToggleButton, the parent of JCheckBox, works well for this, as each button knows its selected state. You can nest GridLayout instances in a vertical Box, as shown below.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.UIManager;
import javax.swing.border.TitledBorder;
/** #see http://stackoverflow.com/a/16733710/230513 */
public class Test {
private static final int N = 4;
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Box b = new Box(BoxLayout.Y_AXIS);
b.add(createPanel());
b.add(createPanel());
f.add(new JScrollPane(b){
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 500);
}
});
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private JPanel createPanel() {
JPanel p = new JPanel(new GridLayout(N, N));
p.setBorder(new TitledBorder(String.valueOf(p.hashCode())));
for (int i = 0; i < N * N; i++) {
p.add(createButton());
}
return p;
}
private JToggleButton createButton() {
JToggleButton b = new JToggleButton(new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
}
});
b.setIcon(UIManager.getIcon("html.pendingImage"));
b.setText(String.valueOf(b.hashCode()));
b.setHorizontalTextPosition(JToggleButton.CENTER);
b.setVerticalTextPosition(JToggleButton.BOTTOM);
return b;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}

Categories