public class Main {
public static class GUI extends JFrame {
public GUI() {
//Title
super("Draw Card");
//panel
Panel buttonsPanel = new Panel();
Panel imagePanel = new Panel();
//App layout
setSize(600,480);
setLayout(new GridBagLayout());
GridBagConstraints gc = new GridBagConstraints();
//gc value
gc.gridy=0;gc.gridx=0;gc.gridwidth=1;gc.gridheight=1;gc.weightx=0.5;gc.weighty=0;gc.fill = GridBagConstraints.HORIZONTAL;
//layout in layout
GridLayout buttonsLayout = new GridLayout(1,2);
GridLayout imageLayout = new GridLayout(4,13);
buttonsPanel.setLayout(buttonsLayout);
imagePanel.setLayout(imageLayout);
//add
add(buttonsPanel,gc);
//change gc value
gc.gridy=1;gc.weighty=1;gc.gridheight=9;gc.fill = GridBagConstraints.BOTH;
//add
add(imagePanel,gc);
//button
JButton btn = new JButton("Draw card");
buttonsPanel.add(btn);
buttonsPanel.add(new JButton("Remove cards."));
//event
btn.addActionListener(e ->{
//just image from link
Image image = null;
try {
URL url = new URL("https://www.improvemagic.com/wp-content/uploads/2020/11/kj.png");
image = ImageIO.read(url);
} catch (IOException ee) {
ee.printStackTrace();
}
//add to label then add label to panel
JLabel label = new JLabel(new ImageIcon(image));
imagePanel.add(label);
revalidate();
});
//set visible
setVisible(true);
}
}
public static void main(String[] args){
GUI test = new GUI();
}
}
EDITED: I dont think i can make it shorter without destroying everything, only one image and it's online, got the same problem that i have.
I've tryed a couple a thing on the pannel and the layout to give the image size for each cell but didnt worked.
Hello ! I have some trouble to keep the full image, i didn't find a single way of getting them fully, did I miss something about those layout ?
I'm still not used to post here ask me if i need to add things ! Thank you !
I have a baglayout that contain 2 gridlayout (one for button and another one where I want to add random card by clicking on one button)
Introduction
I reworked your code to create the following GUI.
Here's the same GUI after drawing a few cards.
The JFrame worked out to be 822 x 420 pixels. In Swing, you work from the inside out. You create Swing components, put the Swing components in JPanels, put the JPanels in a JFrame, and see what the size of the JFrame turns out to be.
Explanation
Whenever I create a Swing GUI, I use the model/view/controller (MVC) pattern. This pattern implies that you create the model first, then the view, then the controller. For complex projects, the process is more iterative than waterfall.
The MVC pattern in Swing development means:
The view reads information from the model.
The view does not modify the model.
The controller modifies the model and updates the view.
There's usually not one controller class "to rule them all". Each Action or ActionListener class is responsible for its portion of the model and the view.
Model
I assumed you eventually wanted to read more than one card image, so I created a Card class. This class holds the card Image and whatever information you want about a playing card, including descriptive text, suit, int value, and int suit value.
I created a SomeCardGameModel class to hold a blank card, a card, and an int cardCount. The cardCount helps ensure that we don't draw more than 52 cards.
Reducing the size of the card image turned out to be a bit of a challenge. I used a search engine to find relevant bits of code and put them together in the SomeCardGameModel class. The main point is that you do all of the model creation before you create the view.
View
I started the Swing application with a call to the SwingUtilities invokeLater method. This method ensures that the Swing components will be created and executed on the Event Dispatch Thread.
I separated the creation of the JFrame and the JPanels into separate methods. This makes the code much easier for people to understand what you're doing.
The JFrame has a default BorderLayout. I used a BorderLayout for the main JPanel and GridLayouts for the button JPanel and the card JPanel. I added some spacing between the Swing components so you can see individual cards.
Controller
After creating a model and a view, your anonymous controller class is simplified. You should be able to create the controller for the "remove Cards" JButton.
Code
Here's the complete runnable code. I made all the additional classes inner classes so I can post this code as one block.
import java.awt.BorderLayout;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SomeCardGame implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new SomeCardGame());
}
private JLabel[] cardLabels;
private final SomeCardGameModel model;
public SomeCardGame() {
this.model = new SomeCardGameModel();
}
#Override
public void run() {
JFrame frame = new JFrame("Draw Card");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
System.out.println(frame.getSize());
}
public JPanel createMainPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
panel.add(createButtonPanel(), BorderLayout.NORTH);
panel.add(createCardPanel(), BorderLayout.CENTER);
return panel;
}
public JPanel createButtonPanel() {
JPanel panel = new JPanel(new GridLayout(0, 2, 5, 5));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JButton drawButton = new JButton("Draw card");
panel.add(drawButton);
drawButton.addActionListener(e -> {
int count = model.getCardCount();
if (count < 52) {
cardLabels[model.getCardCount()].setIcon(
new ImageIcon(model.getCard().getCardImage()));
model.incrementCardCount(1);
}
});
JButton removeButton = new JButton("Remove cards");
panel.add(removeButton);
return panel;
}
public JPanel createCardPanel() {
JPanel panel = new JPanel(new GridLayout(0, 13, 5, 5));
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
this.cardLabels = new JLabel[52];
for (int index = 0; index < cardLabels.length; index++) {
cardLabels[index] = new JLabel(new ImageIcon(
model.getBlankCard().getCardImage()));
panel.add(cardLabels[index]);
}
return panel;
}
public class SomeCardGameModel {
private int cardCount;
private final Card blankCard;
private final Card card;
public SomeCardGameModel() {
this.blankCard = new Card(createBlankCard());
BufferedImage image = readCard();
Image reducedImage = image.getScaledInstance(
56, 78, Image.SCALE_SMOOTH);
this.card = new Card(toBufferedImage(reducedImage));
this.cardCount = 0;
}
private BufferedImage createBlankCard() {
BufferedImage image = new BufferedImage(56, 78,
BufferedImage.TYPE_INT_RGB);
return image;
}
private BufferedImage readCard() {
try {
URL url = new URL("https://www.improvemagic.com/"
+ "wp-content/uploads/2020/11/kj.png");
return ImageIO.read(url);
} catch (IOException ee) {
ee.printStackTrace();
return null;
}
}
private BufferedImage toBufferedImage(Image img) {
if (img instanceof BufferedImage) {
return (BufferedImage) img;
}
BufferedImage bimage = new BufferedImage(
img.getWidth(null), img.getHeight(null),
BufferedImage.TYPE_INT_RGB);
// Draw the image on to the buffered image
Graphics2D bGr = bimage.createGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();
// Return the buffered image
return bimage;
}
public Card getBlankCard() {
return blankCard;
}
public Card getCard() {
return card;
}
public int getCardCount() {
return cardCount;
}
public void incrementCardCount(int increment) {
this.cardCount += increment;
}
}
public class Card {
private final BufferedImage cardImage;
public Card(BufferedImage cardImage) {
this.cardImage = cardImage;
}
public BufferedImage getCardImage() {
return cardImage;
}
}
}
Related
I wanted to create a simple TicTacToe game in java by myself.
But currently I´m struggling with the first issue..
The GUI only displays the Gamefield itself (the "grid") OR the invisble buttons (when you click on them, it displays a X or O)
But never both of them?
I need the gamefield Image as the background and on that the buttons.. But I cant get it working.. I already tried using a third JPanel as the "main" panel with a FlowLayout and added the two other panels onto it.
I created some simple icons and a backround grid in paint.. icons are 200x200 and the grid 600x600 (same as my frame size)
"X-icon" : https://i.stack.imgur.com/tGlZM.png
"O-icon" : https://i.stack.imgur.com/mnoQd.png
"Background" : https://i.stack.imgur.com/BF5yW.png
I Hope anyone can help me out :)
import java.util.ArrayList;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TicTacToe implements ActionListener{
ArrayList<JButton> buttons = new ArrayList<JButton>();
JFrame frame;
JPanel gamefield;
JPanel background;
JLabel backgroundLabel;
ImageIcon backgroundImage = new ImageIcon("C:\\Users\\adnan\\Programmieren\\Games\\TicTacToe\\field.png");
ImageIcon iconX = new ImageIcon("C:\\Users\\adnan\\Programmieren\\Games\\TicTacToe\\iconX.png");
ImageIcon iconO = new ImageIcon("C:\\Users\\adnan\\Programmieren\\Games\\TicTacToe\\iconO.png");
int player = 1;
void createGameField(){
background = new JPanel();
background.setPreferredSize(frame.getSize());
backgroundLabel = new JLabel(backgroundImage);
backgroundLabel.setSize(frame.getSize());
background.add(backgroundLabel);
gamefield = new JPanel();
gamefield.setLayout( new GridLayout(3,3,25,25));
createButtons();
frame.add(background);
frame.add(gamefield);
}
void createButtons(){
for(int index = 0; index<=9; index++){
buttons.add(new JButton());
if(index!=0){
buttons.get(index).setOpaque(false);
buttons.get(index).setContentAreaFilled(false);
buttons.get(index).setBorderPainted(false);
gamefield.add(buttons.get(index));
buttons.get(index).addActionListener(this);
}
}
}
public void actionPerformed(ActionEvent e){
if(e.getSource() instanceof JButton){
if(player==1){
System.out.println( ((JButton) e.getSource()).getText() + "was clicked by player "+player);
((JButton) e.getSource()).setEnabled(false);
((JButton) e.getSource()).setIcon(iconX);
player++;
}
else{
System.out.println( ((JButton) e.getSource()).getText() + "was clicked by player "+player);
((JButton) e.getSource()).setEnabled(false);
((JButton) e.getSource()).setIcon(iconO);
player--;
}
}
}
public TicTacToe(){
frame = new JFrame();
createGameField();
frame.setSize(600,600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
frame.setTitle("TicTacToe");
frame.setResizable(false);
}
public static void main(String[] args) {
TicTacToe newGame = new TicTacToe();
}
}
A FlowLayout will ensure your components will be rendered side by side.
Instead, on the panel that hosts all your UI elements, override paintComponent() so it fills the background with your image. The component will still render it's children (the UI elements) on top of that.
Another chance would be to stack components on top of each other. The lower one would render your image, the upper one the UI - and do not forget to set opaque=false to the UI.
I am trying to create a Blackjack app with swing and I am having difficulty adding new cards when a player clicks hit button. I feel like it has something to do with the JLabel not being validated but I have no idea what that really means or how to fix the issues. Please help...
I am really new to Java swing so it might seem very intuitive problems but I hope someone can explain kindly...
Below is the code that I currently have and it deals two cards each for both dealer and player without duplication of cards but is unable to display newly dealt cards even though the card is chosen as I can see them on console...
import javax.swing.*;
import java.awt.*;
#SuppressWarnings("serial")
public class PlayerHand extends JPanel {
//declaring private vars
private JLabel cardPonTable[] = new JLabel[11];
private int cardP[] = new int[11];
private Image cardPImage[] = new Image[11];
private int cardOnTableCount = 0; //counter for number of cards on the table
public PlayerHand(boolean firstDeal){
setLayout(null);
/**
* Deals the first two cards for the player
*/
if (firstDeal == true) { //run this code if true
//playerHand config
setBackground(new Color(238, 238, 238));
setLayout(null);
JLabel playersHandLabel = new JLabel("Player's Hand"); //creates a label indicating the bottom half of the screen is the player's hand
//player's hand label config
playersHandLabel.setFont(new Font("Lucida Grande", Font.PLAIN, 25));
playersHandLabel.setHorizontalAlignment(SwingConstants.CENTER);
playersHandLabel.setBounds(192, 314, 200, 80);
add(playersHandLabel); //add player's hand label to the container
//creates JLabel for two of the player's card, set the positions, and add to the container
cardPonTable[0] = new JLabel("");
cardPonTable[0].setBounds(80, 6, 220, 320);
add(cardPonTable[0]);
cardPonTable[1] = new JLabel("");
cardPonTable[1].setBounds(340, 6, 220, 320);
add(cardPonTable[1]);
System.out.println("Player's cards"); //indicate that the following is the player's dealt card on the console
CardDeal.createDeck(); //create a deck
//deal two card for the player
cardP[0] = CardDeal.cardDeal();
cardP[1] = CardDeal.cardDeal();
//get the image from the src folder
cardPImage[0] = new ImageIcon (this.getClass().getResource(cardP[0]+".png")).getImage();
cardPImage[1] = new ImageIcon (this.getClass().getResource(cardP[1]+".png")).getImage();
cardPonTable[0].setIcon(new ImageIcon (cardPImage[0])); //set the JLabel of the card to the image chosen above
cardOnTableCount++; //increase the counter by one
cardPonTable[1].setIcon(new ImageIcon (cardPImage[1])); //set the JLabel of the card to the image chosen above
cardOnTableCount++; //increase the counter by one
}
/**
* Do not deal the first two cards (instance made)
*/
}
public void cardAdded() throws Exception {
//cardP1onTable.setBounds(cardP1onTable.getX()-50, cardP1onTable.getY(), (int)(WIDTH*0.7), (int)(HEIGHT*0.7));
//cardP2onTable.setBounds(cardP2onTable.getX()-50, cardP2onTable.getY(), (int)(WIDTH*0.7), (int)(HEIGHT*0.7));
PlayerHand newDealt = new PlayerHand(false); //creates an instance of playerHand method (send false as a parameter so that the method won't deal two cards again)
System.out.println("Player's card dealt");
newDealt.setLayout(null);
cardPonTable[cardOnTableCount] = new JLabel("");
cardPonTable[cardOnTableCount].setBounds(192, 6, 220, 320);
newDealt.add(cardPonTable[cardOnTableCount]);
cardP[cardOnTableCount] = CardDeal.cardDeal();
cardPImage[cardOnTableCount] = new ImageIcon (newDealt.getClass().getResource(cardP[cardOnTableCount]+".png")).getImage();
cardPonTable[cardOnTableCount].setIcon(new ImageIcon (cardPImage[cardOnTableCount]));
cardOnTableCount++;
}
}
This code below is the JPanel that lets the player choose hit or stay
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JPanel;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
#SuppressWarnings("serial")
public class ChoiseBar extends JPanel{
private JButton hitButton;
private JButton stayButton;
public ChoiseBar() {
Dimension dim = getPreferredSize();
dim.height = 100;
setPreferredSize(new Dimension(1200, 100));
hitButton = new JButton("HIT");
hitButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
PlayerHand.cardAdded();
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
stayButton = new JButton("STAY");
setLayout(new GridLayout(0, 2, 0, 0));
add(hitButton);
add(stayButton);
}
}
This is the MainFrame class where PlayerHand, DealerHand, and ChoiceBar is added.
import javax.swing.JFrame;
import java.awt.Color;
#SuppressWarnings("serial")
public class MainFrame extends JFrame{
//declaring private vars
private DealerHand dealerHand;
private PlayerHand playerHand;
private ChoiseBar choiseBar;
public MainFrame() {
super("TABLE"); //calling the "TABLE" method in BJ_APP
playerHand = new PlayerHand(true); //creates an instance of playerHand (firstDeal is true as it is the first deal)
//playerHand config
playerHand.setForeground(new Color(0, 0, 0));
playerHand.setBackground(new Color(238, 238, 238));
playerHand.setLocation(300, 625);
playerHand.setSize(600, 400);
dealerHand = new DealerHand(); //creates an instance of dealerHand
//playerHand config
dealerHand.setLocation(300, 31);
dealerHand.setSize(600, 429);
choiseBar = new ChoiseBar(); //creates an instance of choiseBar
//choiseBar config
choiseBar.setSize(800, 120);
choiseBar.setLocation(214, 472);
getContentPane().setLayout(null); //mainFrame uses absolute layout
//add these three containers to mainFrame
getContentPane().add(choiseBar);
getContentPane().add(playerHand);
getContentPane().add(dealerHand);
setSize(1200,1080); //set the size of mainFrame
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //the program will terminated when mainFrame is closed
this.setVisible(true); //set mainFrame visible
}
}
What exactly does "keeping a reference" mean?
You do it all the time:
hitButton = new JButton("HIT");
Above you create an instance of a JButton a keep a reference to it.
Then in your code you change a property of the button by using:
hitButton.addActionListener(new ActionListener() ...
Your custom panels are no different. You create a custom class with methods that you want to execute.
So somewhere in your code you need logic like:
PlayHand playHandPanel = new PlayHand();
ChoiceBar choiceBarPanel = new ChoiceBar( playHandPanel );
frame.add( playHandPanel );
frame.add( choiceBar );
Then in the constructor of your ChoiceBar you save the reference to the "playHandPanel" as an instance variable in your class. And then in the ActionListener for the button you can now invoke the cardAdded() method.
I want to put my background image at the very bottom in this frame, and the button on top. However the code I wrote below doesn't work. Can anyone see where the problems are?
Another thing is that even though I set the location for my button, it keep showing at the top center on the frame.
Please ignore the comment lines. (I was just guessing, and hoping them will work, but they don't apparently.)
public class Menu extends JFrame{
private JLayeredPane pane;
private JLayeredPane pane2;
public Menu(){
final JFrame f = new JFrame("Chinese Chess");
JButton play = new JButton("Play vs. AI");
f.setLayout(new FlowLayout());
f.setLocationRelativeTo(null);
f.setSize(800, 800);
f.setVisible(true);
f.setResizable(false);
//f.pack();
pane = new JLayeredPane();
pane2 = new JLayeredPane();
f.add(pane);
f.add(pane2);
//background image
JLabel background = new JLabel(new ImageIcon("res/img/background.png"));
background.setLocation(0, 0);
background.setSize(800, 800);
pane.add(background, JLayeredPane.FRAME_CONTENT_LAYER);
pane2.add(play, JLayeredPane.DEFAULT_LAYER);
//pane.moveToBack();
//button PlayAI
play.setLocation(500,500);
play.setPreferredSize(new Dimension(100,50));
//f.setLayout(new FlowLayout());
//frame menu
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//f.getContentPane().add(play);
play.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
new PlayAI();
}
});
}
public static void main(String[] args){
new Menu();
}
Problems/Solutions:
setLocation(...) and setBounds(...) types of calls are ignored by most layout managers. The only way to use them is to set the layout of the container to null via .setLayout(null);
But having said that, while null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one.
So in sum -- don't do this, don't use null layouts or setBounds, but rather nest JPanels, each using its own layout manager, and thereby create easy to maintain and decent GUI's.
If you want an image to be in the background, then draw it in a JPanel that you use as a container for your GUI components by drawing it in the JPanel's paintComponent(Graphics g) method as has been demonstrated in many many similar questions on this site -- I'll find you some of mine in a second.
If you add any JPanels on top of this image drawing JPanel, be sure that you can see through them by calling setOpaque(false) on these overlying JPanels. Otherwise you'll cover up the image.
Your code has two JFrames when only one is needed. Get rid of the one you don't use.
You call setVisible(true) too early on the JFrame, before components have been added to the GUI -- don't. Call it only after adding everything to the GUI so all display OK.
You're creating two JLayedPanes, and completely covering one by the other by adding them to the JFrame without understanding how the JFrame's BorderLayout handles added components.
I suggest that you not even use one JLayeredPane but instead draw in the JPanel as noted above, and use that as your container.
Your code looks to be opening a completely new GUI window when the play button is pressed, and if so, this can get annoying to the user fast. Consider swapping views instead with a CardLayout.
For example:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
// extend JPanel so you can draw to its background
#SuppressWarnings("serial")
public class Menu2 extends JPanel {
private BufferedImage bgImage = null; // our background image
private JButton playButton = new JButton(new PlayVsAiAction("Play Vs. AI", KeyEvent.VK_P));
public Menu2(BufferedImage bgImage) {
this.bgImage = bgImage;
setLayout(new GridBagLayout()); // center our button
add(playButton);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bgImage != null) {
g.drawImage(bgImage, 0, 0, this);
}
}
// to size our GUI to match a constant or the image.
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
// if you want to size it based on the image
if (bgImage != null) {
int width = bgImage.getWidth();
int height = bgImage.getHeight();
return new Dimension(width, height);
} else {
return super.getPreferredSize();
}
// if you want to size the GUI with constants:
// return new Dimension(PREF_W, PREF_H);
}
private class PlayVsAiAction extends AbstractAction {
public PlayVsAiAction(String name, int mnemonic) {
super(name); // have our button display this name
putValue(MNEMONIC_KEY, mnemonic); // alt-key to press button
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO code to start program
}
}
private static void createAndShowGui() {
BufferedImage img = null;
String imagePath = "res/img/background.png";
try {
// TODO: fix this -- use class resources to get image, not File
img = ImageIO.read(new File(imagePath));
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
Menu2 mainPanel = new Menu2(img);
JFrame frame = new JFrame("Chinese Chess");
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();
});
}
}
Apart from the solution above... you should create and launch your swing application this way:
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
// Instantiate your JFrame and show it
}
I'm attempting to change the color of the border of a JTabbedPane based on the selected tab. Using answers here and on the web, I've managed this:
import java.awt.*;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
public class TabbedPaneTest implements Runnable {
JTabbedPane pane = new JTabbedPane();;
public void run() {
// magenta border first so any changes will be obvious
setTabbedPaneBorderColor(new Color(255, 0, 255));
JPanel container = new JPanel();
container.setSize(new Dimension(500, 200));
pane.setPreferredSize(new Dimension(400, 200));
pane.addTab("A", createTab(Color.RED));
pane.addTab("B", createTab(Color.YELLOW));
pane.addTab("C", createTab(Color.BLUE));
pane.addChangeListener(new TabSelected());
container.add(pane);
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(container);
frame.setSize(500, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JPanel createTab(Color color) {
JPanel p = new JPanel();
p.setBorder(BorderFactory.createLineBorder(color, 2));
return p;
}
private class TabSelected implements ChangeListener {
#Override
public void stateChanged(ChangeEvent e) {
int index = pane.getSelectedIndex();
switch (index) {
case 0:
setTabbedPaneBorderColor(Color.RED);
break;
case 1:
setTabbedPaneBorderColor(Color.YELLOW);
break;
case 2:
setTabbedPaneBorderColor(Color.BLUE);
break;
}
}
}
public void setTabbedPaneBorderColor(Color tabBorderColor) {
UIManager.put("TabbedPane.borderHightlightColor", tabBorderColor);
UIManager.put("TabbedPane.darkShadow", tabBorderColor);
UIManager.put("TabbedPane.shadow", tabBorderColor);
UIManager.put("TabbedPane.light", tabBorderColor);
UIManager.put("TabbedPane.highlight", tabBorderColor);
UIManager.put("TabbedPane.focus", tabBorderColor);
UIManager.put("TabbedPane.selectHighlight", tabBorderColor);
pane.setUI(new BasicTabbedPaneUI() {
#Override
protected void installDefaults() {
super.installDefaults();
highlight = UIManager.getColor("TabbedPane.light");
lightHighlight = UIManager.getColor("TabbedPane.highlight");
shadow = UIManager.getColor("TabbedPane.shadow");
darkShadow =UIManager.getColor("TabbedPane.darkShadow");
focus = UIManager.getColor("TabbedPane.focus");
}
});
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new TabbedPaneTest());
}
}
In particular, the setTabbedPaneBorderColor() method does exactly what I wanted (that is, it modifies the fancy border around the tabs, rather than the border on the panels contained in it or a plain rectangular border around the entire space the JTabbedPane occupies). For some reason this example throws an error that doesn't show up in my actual program (I think it's related to the SwingWorker and EDT). Now I'm trying to figure out how to change the selected tab's background.
The relevant property is
UIManager.put("TabbedPane.selected",Color.MAGENTA);
However, I don't seem to have a way to use that in the tabUI (it's baffling, but there's no background Color variable in BasicTabbedPaneUI).
Edit: Hopefully someone more knowledgeable will come by with a good answer, but if you googled this my current solution is to use a neutral color for the selected tab's background color since there seems to be no simple way to update it. I also switched to a neutral tab border (even though you CAN update that as the example shows) and created the colored borders inside the contained JPanels. It's not ideal, but it looks pretty good and I don't have time to continue looking for a cleaner solution at the moment.
This is worked for me
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Enabled].backgroundPainter", new BackgroundPainter(Color.white));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Enabled+MouseOver].backgroundPainter", new BackgroundPainter(Color.white));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Enabled+Pressed].backgroundPainter", new BackgroundPainter(Color.white));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Focused+MouseOver+Selected].backgroundPainter", new BackgroundPainter(Color.white));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Focused+Pressed+Selected].backgroundPainter", new BackgroundPainter(Color.white));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Focused+Selected].backgroundPainter", new BackgroundPainter(Color.GRAY));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[MouseOver+Selected].backgroundPainter", new BackgroundPainter(Color.white));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Pressed+Selected].backgroundPainter", new BackgroundPainter(Color.white));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Selected].backgroundPainter", new BackgroundPainter(Color.white));
BackgroundPainter class
public class BackgroundPainter implements Painter<JComponent> {
private Color color = null;
BackgroundPainter(Color c) {
color = c;
}
#Override
public void paint(Graphics2D g, JComponent object, int width, int height) {
if (color != null) {
g.setColor(color);
g.fillRect(0, 0, width - 1, height - 1);
}
}
}
for me, it worked, I just set the UImanager's TabbedPane.selected color property before creation of JTabbedPane object.
UIManager.put("TabbedPane.selected", Color.red);
tabbedPane = new JTabbedPane();
Refer this link, i'm sure it will work for you too.
http://esus.com/changing-the-color-of-the-selected-tab-of-a-jtabbedpane/
I would like to display more than one image on the screen in the same JPanel.
A for loop iterates over each element in the array and displays their corresponding image, but only seems to keep the last image.
The code:
import javax.swing.*;
import java.awt.*;
import java.io.*;
import javax.imageio.ImageIO;
public class GameGUI extends JFrame{
JPanel mainPanel = new JPanel();
JPanel buttonPanel = new JPanel();
int arrayLength;
public GameGUI() {
super("Gameplay");
//Set size of the frame.
setSize(650, 580);
//Location inside frame.
setLocation(10, 8);
SwingUtilities.isEventDispatchThread();
The methods that contain each individual panel:
createMainPanel();
createCentrePanel();
createNorthPanel();
createSouthPanel();
createWestPanel();
createEastPanel();
setVisible(true);
}
//creating panels
public void createMainPanel() {
//here is the main panel which the others will be nested in.
mainPanel.setLayout(new BorderLayout());
mainPanel.setBackground(Color.red);
add(mainPanel);
}
public boolean createCentrePanel() {
JPanel CENTRE = new JPanel(new BorderLayout());
CENTRE.setBackground(Color.WHITE);
CENTRE.setBorder(BorderFactory.createLineBorder(Color.black));
mainPanel.add(CENTRE, BorderLayout.CENTER);
return true;
}
This is the panel which i am using to print multiple images to the panel.
As you can see I have a for loop which is going through each item in the array and passing the value to the draw component. However it only seems to keep the last image on the screen eventhough each item in the array is being passed to it.
I have tried using repaint but it doesn't seem to work:
public boolean createNorthPanel() {
int[] array = {1, 8, 9, 10};
arrayLength = array.length;
int size = 0;
JPanel NORTH = new JPanel(new BorderLayout());
NORTH.setPreferredSize(new Dimension(100, 100));
NORTH.setBorder(BorderFactory.createLineBorder(Color.black));
mainPanel.add(NORTH, BorderLayout.NORTH);
for (int i = 0; i < arrayLength; i++) {
NORTH.add(new drawPanel(array[i], size, arrayLength));
size = size + 30;
//repaint();
}
return true;
}
public boolean createSouthPanel() {
JPanel SOUTH = new JPanel(new BorderLayout());
SOUTH.setPreferredSize(new Dimension(100, 100));
// SOUTH.add(new drawPanel(2, 0));
// SOUTH.add(new drawPanel(5, 30));
SOUTH.setBorder(BorderFactory.createLineBorder(Color.black));
mainPanel.add(SOUTH, BorderLayout.SOUTH);
SOUTH.add(buttonPanel, BorderLayout.EAST);
return true;
}
public boolean createWestPanel() {
JPanel WEST = new JPanel(new BorderLayout());
WEST.setPreferredSize(new Dimension(150, 100));
//WEST.add(new drawPanel(8, 0));
WEST.setBorder(BorderFactory.createLineBorder(Color.black));
mainPanel.add(WEST, BorderLayout.WEST);
return true;
}
public boolean createEastPanel() {
JPanel EAST = new JPanel(new BorderLayout());
EAST.setPreferredSize(new Dimension(150, 100));
EAST.setBorder(BorderFactory.createLineBorder(Color.black));
mainPanel.add(EAST, BorderLayout.EAST);
//EAST.add(new drawPanel(2, 0));
//EAST.add(new drawPanel(7, 60));
return true;
}
public static void main(String args[]){
new GameGUI();
}
}
Here is my class which draws the images on the screen
class drawPanel extends JPanel {
Image image = null;
int xPos;
public drawPanel(int x, int y, int length) {
xPos = y;
try {
File location = new File("src/Card_images/" + x + ".png");
image = ImageIO.read(location);
} catch (IOException e) {
System.out.println("Error: " + e);
}
}
/*public Dimension getPreferredSize() {
return new Dimension(71, 96);
}*/
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//draws image to screen at positions displayed
g.drawImage(image, xPos, 0, this);
}
}
You only have a single drawImage() statement that is executed in you paintCompent() method so you only ever see the last image drawn.
See Custom Painting Approaches for two different ways to draw multiple objects. You will obviously need to customize for your requirements, but the basic concepts will be the same.
Edit:
The above does not apply to your question, but is still good to know when you do need to do some custom painting.
Sorry, because of the custom painting I misread your question. You are making the code too complex.
The first problem is that you changed the layout manager of the "north" panel to a BorderLayout. You can only add a single component to any location of a BorderLayout. So that is why the last component added gets painted. Just use the default FlowLayout for the panel. Although your code still won't work because your components don't have a preferred size.
So the solution to your problem is:
a) create a panel using a FlowLayout
b) Use a JLabel to display your images. There is no need to do custom painting!. Add the labels to the panel, then add this panel to your frame.
Now the layout manager can do its job and you don't need to worry about the details.
Also, use standard Java naming conventions. Your code is too hard to read because you don't follow the standards.
NORTH is not a proper variable name. It should be "north". An upper cased name indicates a final static variable.
use proper class names. Classes should start with an upper case character. "drawPanel" should be "DrawPanel".