I have problem with creating own swing component. I want to create component that will render some image and it will fit current window (or container) size proportionally.
The problem is that I cant know real available space for component in container (without insents, borders, may be something else...).
This example shows the problem:
public class Main
{
static class MyComponent extends JComponent
{
#Override
public Dimension getPreferredSize()
{
if(isShowing())
{
int width = getParent().getSize().width - 4;
Dimension dimension = new Dimension(width, (int)(width / 0.8));
System.out.println(dimension);
return dimension;
}
return super.getPreferredSize();
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.RED);
g.fillOval(0, 0, getWidth(), getHeight());
}
}
public static void main(String... args)
{
JFrame frame = new JFrame("Test");
JPanel panel = new JPanel(new GridBagLayout());
panel.setBackground(Color.DARK_GRAY);
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(2, 2, 2, 2);
c.gridx = c.gridy = 0;
panel.add(new MyComponent(), c);
c.gridy++;
panel.add(new MyComponent(), c);
frame.add(new JScrollPane(panel));
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.setVisible(true);
}
}
If you remove 4 (left & right from insets) from getParent().getSize().width - 4 expression and launch, you will see that component(s) will increase its size infinitely.
In the above code I get full width of container, but I need available width so that component will not trigger container to resize again and again.
Or is there another way to fit component normally?
Related
I have a class that extends JFrame and I would like to add two JPanels to that JFrame: a text panel and a graphics panel. My text panel is a panel containing a label with text. My graphics panel will contain a graph (created using 2DGraphics). I'm adding the graphic panel to the left side (0,0) and the text panel to right side (1,0) using a gridbaglayout method. However, the graphic panel won't show up in the frame. I have tried numerous methods to try to get the panel to show up with no success.
import java.awt.*;
import javax.swing.*;
public class GraphicsTest extends JFrame {
private final JPanel textPanel;
private final JLabel textLabel;
public GraphicsTest() {
textPanel = new JPanel(new BorderLayout());
textLabel = new JLabel("Home label");
this.setBounds(180, 112, 1080, 675);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new GridBagLayout());
textPanel.add(textLabel, BorderLayout.NORTH);
addComponent(this, new GraphicPanel(), 0, 0, 1, 1, GridBagConstraints.CENTER);
addComponent(this, textPanel, 1, 0, 1, 1, GridBagConstraints.CENTER);
this.setVisible(true);
}
public class GraphicPanel extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public void paintComponents(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
// drawing lots of shapes and lines, removed for readibility
}
}
public void addComponent(JFrame frame, JComponent component, int x, int y, int width, int height, int align) {
GridBagConstraints c = new GridBagConstraints();
c.gridx = x;
c.gridy = y;
c.gridwidth = width;
c.gridheight = height;
c.weightx = 100.0;
c.weighty = 100.0;
c.insets = new Insets(5, 0, 5, 0);
c.anchor = align;
c.fill = GridBagConstraints.NONE;
frame.add(component, c);
}
public static void main(String[] args) {
GraphicsTest gui = new GraphicsTest();
}
}
Works fine for me when I use a size like (200, 200).
GridbagLayout works such that if a component can't be displayed at its preferred size, then it will be displayed at its minimum size, which would be (0, 0).
So whether (700, 700) works will depend on your screen resolution. It also works at (700, 600) for my screen.
I question if you want to use a GridBadLayout. Maybe just use a BorderLayout. The custom painting panel would go in the CENTER so it will grow/shrink as the frame size changes. The other panel would go to the LINE_END, so it will remain at a fixed size.
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?
My goal is to have a window with 2 panels in different colors in the background. They each cover a specific percentage of the screen and this changes periodically. I did this by creating a JSplitPane. But now I want to add a JLabel showing some data in front of all of this in the middle of the screen. How would I do this?
How about using the JLayer: How to Decorate Components with the JLayer Class (The Java™ Tutorials > Creating a GUI With JFC/Swing > Using Other Swing Features)
import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.*;
public class JLayerTest {
public Component makeUI() {
JSplitPane splitPane = new JSplitPane();
splitPane.setResizeWeight(.4);
splitPane.setLeftComponent(makeLabel(Color.RED));
splitPane.setRightComponent(makeLabel(Color.GREEN));
//splitPane.setEnabled(false);
//splitPane.setDividerSize(0);
JPanel rubberStamp = new JPanel();
JLabel label = makeLabel(Color.BLUE);
label.setText("JLabel");
label.setForeground(Color.WHITE);
label.setBorder(BorderFactory.createLineBorder(Color.BLUE, 50));
LayerUI<JSplitPane> layerUI = new LayerUI<JSplitPane>() {
#Override public void paint(Graphics g, JComponent c) {
super.paint(g, c);
Dimension d = label.getPreferredSize();
int x = (c.getWidth() - d.width) / 2;
int y = (c.getHeight() - d.height) / 2;
SwingUtilities.paintComponent(g, label, rubberStamp, x, y, d.width, d.height);
}
};
return new JLayer<>(splitPane, layerUI);
}
public static JLabel makeLabel(Color color) {
JLabel label = new JLabel();
label.setOpaque(true);
label.setBackground(color);
return label;
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new JLayerTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
Considering your description, I prefer using a paintComponent approach. You just paint 2 rectangles on the background of components and still positioning components as usual, as simple as this:
JFrame f = new JFrame();
f.setPreferredSize(new Dimension(600, 600));
f.pack();
f.setLayout(new BorderLayout());
JPanel p = new JPanel(new FlowLayout()) {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int perc = (int)((float)getWidth()*0.3f); // set % to fill
g.setColor(Color.RED);
g.fillRect(0, 0, perc, g.getClipBounds().height);
g.setColor(Color.BLUE);
g.fillRect(perc, 0, getWidth()-perc, getHeight());
}
};
f.add(p);
p.add(new JButton("test"));
f.setVisible(true);
My example does it on a JPanel but it can be done directly on JFrame and then puts a JButton over it using a FlowLayout. Here is the result:
I am trying to paint two squares of defined size, one located next to another in a row, using paintComponent() method of JPanel.
Here what I tried so far:
1. BorderLayout
I tried to draw each square in a separate subclass of JPanel, and then add these JPanels to a JFrame.
Result: squares are squashed to the opposite sides of JPanel: height is as expected but width is minimal.
JFrame frame = new JFrame();
GreenPanel greenPanel = new GreenPanel();
frame.getContentPane().add(BorderLayout.WEST, greenPanel);
BluePanel bluePanel = new BluePanel();
frame.getContentPane().add(BorderLayout.EAST, bluePanel);
frame.setSize(500, 350);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
class GreenPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.GREEN);
g.fillRect(0, 0, 100, 100);
}
}
class BluePanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.BLUE);
g.fillRect(0, 0, 100, 100);
}
}
2. FlowLayout
I tried to add my "children" JPanels with painted squares to a "parent" JPane and then call JFrame.setContentPane(JPanel).
Result: squares are painted in top-center region as tiny squares.
JFrame frame = new JFrame();
JPanel outerPanel = new JPanel();
frame.setContentPane(outerPanel);
GreenPanel greenPanel = new GreenPanel();
outerPanel.add(greenPanel);
BluePanel bluePanel = new BluePanel();
outerPanel.add(bluePanel);
frame.setSize(500, 350);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
class GreenPanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.GREEN);
g.fillRect(0, 0, 100, 100);
}
}
class BluePanel extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.BLUE);
g.fillRect(0, 0, 100, 100);
}
}
What am I doing wrong? Is there any way I can force layout managers to respect the size of the squares painted with paintComponent() ?
Make the following changes. See comments for explanations.
JFrame frame = new JFrame();
//add layout manager. You can achieve the desired layout
//with GridLayout, Box layout and others
frame.getContentPane().setLayout(new GridLayout(1,2));
GreenPanel greenPanel = new GreenPanel();
//set preferred size to the panel
greenPanel.setPreferredSize(new Dimension(100,100));
frame.add(greenPanel);
BluePanel bluePanel = new BluePanel();
//set preferred size to the panel
bluePanel.setPreferredSize(new Dimension(100,100));
frame.getContentPane().add(bluePanel);
//let the frame adapt to the panels size
//frame.setSize(500, 350);
frame.validate();
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Don't hesitate to ask for clarifications as needed.
(BTW overriding paintComponent(Graphics g) is not really needed. You could simply set preferred size and color to each JPanel)
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);
}