Make JLabel not cover painting - java

I'm trying to make a game of chess, but when I try to insert chess pieces through JLabel icons, they cover the actual chessboard, thus only having the pieces left on screen. How do I make the JLabels not cover up paintings behind it? I'm doing this using a class that extends JApplet.
UPDATE: it worked by using Applet instead of JApplet, though I still have no idea why.
This is the code:
ChessBoard board; // done in another class file
public static int CEL_WIDTH = 65;
public static int MARGIN_X = 50, MARGIN_Y = 50;
imagePos = "../src/Schack/Bilder/";
JLabel label;
public void init() {
setLayout(null);
this.setSize(600, 600);
board = new ChessBoard(MARGIN_X, MARGIN_Y, CEL_WIDTH);
ImageIcon imageIcon = new ImageIcon(getImage(getDocumentBase(), imagePos + "blackRook.png")); //scaling my image
Image image = imageIcon.getImage();
Image newimg = image.getScaledInstance(CEL_WIDTH, CEL_WIDTH, java.awt.Image.SCALE_SMOOTH);
imageIcon = new ImageIcon(newimg);
label = new JLabel(imageIcon);
label.setBounds(MARGIN_X, MARGIN_Y, CEL_WIDTH, CEL_WIDTH);
add(label);
}
#Override
public void paint(Graphics g) {
board.paintChessBoard(g); // another paint method in a different class file
super.paint(g);
}

Related

Making Multi-Coloured Buttons in Java

I want to create a grid of squares in my Java Swing GUI. I need to toggle their state so I'm thinking a JToggleButton is appropriate for each of the squares.
The problem that I have is that I want to partially colour each toggle button according to given percentages. e.g. if 50% and 50% I want the left half of the button to be green and the right to be red. If 25%,25%,50% I'd need 3 colours. I also need to use the button Text field so hiding that isn't allowed in the solution.
Is it possible to do something like this with a JToggleButton? Is there a better element to use? Or how might I go about it?
I apologise for not posting my work so far but I can't find anything close to an example of this type of thing.
I want to end up with something like this where each square is a button.
You can construct a button with changeable 2-color background as required by overriding
paintComponent:
import java.awt.*;
import javax.swing.*;
public class TwoColorsButton extends JButton{
private final Color leftColor, rightColor;
private int percentOfLeftColor;
public TwoColorsButton(String text) {
this(text,Color.RED, Color.GREEN, 50);
}
public TwoColorsButton(String text, Color leftColor,Color rightColor, int percentOfLeftColor) {
super(text);
this.leftColor = leftColor;
this.rightColor = rightColor;
this.percentOfLeftColor = percentOfLeftColor;
//make button transparent
setOpaque(false);
setContentAreaFilled(false);
setBorderPainted(false);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g.create();
int leftWidth = getWidth() * percentOfLeftColor/100;
g2.setColor(leftColor);
g2.fillRect(0, 0, leftWidth , getHeight());
g2.setColor(rightColor);
g2.fillRect(leftWidth, 0, getWidth() -leftWidth, getHeight());
g2.setPaint(Color.BLACK);
super.paintComponent(g2); //button is transparent so super paints text only
g2.dispose();
}
public void setPercentOfLeftColor(int percentOfLeftColor) {
this.percentOfLeftColor = percentOfLeftColor;
repaint();
}
public int getPercentOfLeftColor() {
return percentOfLeftColor;
}
public static void main(String[] args) {
//run button test
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
JPanel topPanel = new JPanel();
TwoColorsButton twoColorBtn = new TwoColorsButton("Some Text");
topPanel.add(twoColorBtn);
frame.add(topPanel, BorderLayout.PAGE_START);
JPanel bottomPanel = new JPanel();
JButton runTestBtn = new JButton("Run test");
runTestBtn.addActionListener(e->{
runTestBtn.setEnabled(false);
new Timer(1000, e1 ->{
int percent = twoColorBtn.getPercentOfLeftColor() +25;
percent = percent > 100 ? 0 : percent;
twoColorBtn.setPercentOfLeftColor(percent);
}).start();
});
bottomPanel.add(runTestBtn);
frame.add(bottomPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setVisible(true);
}
}
The code can easily be modified to allow 3 colors, if needed.
(Test it online here)
(See a basic 3 colors toggle button here)

Setting ImageIcon to full screen

I have made a Board class, where I import an image using ImageIcon and, instead of making a picture with the specified resolution, I want it to be full screen for any type of monitor.
public Board() {
p = new Dude();
addKeyListener(new AL());
setFocusable(true);
ImageIcon i = new ImageIcon("C:/test.jpg");
img = i.getImage();
time = new Timer(5, this);
time.start();
}
I've used this code before:
public class MainMenu2 {
MainMenu2() throws IOException{
JFrame Main_Menu = new JFrame("Main Menu");
Main_Menu.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
final int widthScreen = screenSize.width;
final int heightScreen = screenSize.height;
BufferedImage backgroundImage = ImageIO.read(new File("P://My Pictures//background1.jpg"));
JLabel background = new JLabel(new ImageIcon(backgroundImage));
Image scaleBackground = backgroundImage.getScaledInstance(widthScreen, heightScreen, Image.SCALE_SMOOTH);
ImageIcon imageIcon = new ImageIcon(scaleBackground);
Main_Menu.setContentPane(new JLabel(imageIcon));
which uses scale smooth, which sets the image to the screen width and height, but I don't know how to apply it to my current code. The difference between both is that, Board class extends JPanel, and MainMenu2 is just a normal class, where a JFrame is created, etc. Please help! Thank you.
At the most basic level, it might look some like this...
ImageIcon i = ImageIO.read(new File("C:/test.jpg"));
Image scaleBackground = backgroundImage.getScaledInstance(widthScreen, heightScreen, Image.SCALE_SMOOTH);
img = scaleBackground.getImage();
Now, problems - the size of the component isn't likely to match he size of the screen.
As a preference, I might be tempted to do something like Scale the ImageIcon automatically to label size
You should also read The Perils of Image.getScaledInstance()

Images not visible in JList

I'm writing a little photo application (asked some questions before) and I have one problem which I cannot resolve. The idea is that there are two sections: the upper one is for an overview (using thumbnails) and the lower one shows the selected image in it's full size. I cannot use ImageIO (required by my lecturer).
I'm using a JList for the overview but most images are not visible. I chose a folder with about 20 images and only 2 show up. And one of them isn't even centered.
For some reason, if I delete those lines:
thumbnaillist.setFixedCellWidth(thumbW);
thumbnaillist.setFixedCellHeight(thumbH);
One image shows up that wasn't visible before, but now the other two disappear.
This is my code:
public class PVE extends JFrame {
private JFileChooser fileChoose;
//MenuBar
private JMenuBar menubar;
private JMenu file;
private JMenuItem openFolder;
private JMenuItem exit;
//Thumbnails
private JList thumbnaillist;
private DefaultListModel<ImageIcon> listmodel;
private JScrollPane tscroll;
private ImageIcon thumbs;
private int thumbW = 100;
private int thumbH = 100;
//for full size view
private JPanel imgview;
public PVE() {
setLayout(new BorderLayout());
//MenuBar
menubar = new JMenuBar();
file = new JMenu("File");
openFolder = new JMenuItem("Open folder...");
exit = new JMenuItem("Quit");
file.add(openFolder);
file.addSeparator();
file.add(exit);
menubar.add(file);
setJMenuBar(menubar);
fileChoose = new JFileChooser();
openFolder.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
fileChoose.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
fileChoose.showOpenDialog(null);
File chosenDir = fileChoose.getSelectedFile();
loadToThumbView(chosenDir);
}
});
//Thumbnail view
listmodel = new DefaultListModel();
thumbnaillist = new JList(listmodel);
thumbnaillist.setLayoutOrientation(JList.HORIZONTAL_WRAP);
thumbnaillist.setFixedCellWidth(thumbW);
thumbnaillist.setFixedCellHeight(thumbH);
thumbnaillist.setVisibleRowCount(1);
tscroll = new JScrollPane(thumbnaillist, JScrollPane.VERTICAL_SCROLLBAR_NEVER,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
tscroll.setPreferredSize(new Dimension(0, 100));
add(tscroll, "North");
//for full size view
imgview = new JPanel();
imgview.setBackground(Color.decode("#f7f7f7"));
add(imgview, "Center");
setTitle("Photo Viewer");
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
SwingUtilities.updateComponentTreeUI(this);
} catch (Exception e) {
}
setSize(700, 700);
setLocation(200, 200);
setVisible(true);
}
public void loadToThumbView(File folder) {
listmodel.removeAllElements();
File[] imgpaths = folder.listFiles();
for (int j = 0; j < imgpaths.length; j++) {
listmodel.addElement(resizeToThumbnail(new ImageIcon(imgpaths[j].toString())));
}
}
public ImageIcon resizeToThumbnail(ImageIcon icon) {
Image img = icon.getImage();
BufferedImage bf = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics g = bf.createGraphics();
g.drawImage(img, 0, 0, thumbW, thumbH, null);
ImageIcon kB = new ImageIcon(bf);
return kB;
}
public static void main(String argv[]) {
PVE pv = new PVE();
}
}
Your problem is because of the way you're scaling your images.
I'm not exactly sure why but I guess it has something to do with the BufferedImage#createGraphics() call and that I was able to reproduce the problem with .jpg images while .png files were correctly painted.
However if you scale your images instead of converting them to a BufferedImage and getting a new ImageIcon from it, you get the correct output:
public ImageIcon resizeToThumbnail(ImageIcon icon) {
Image img = icon.getImage();
Image scaled = img.getScaledInstance(thumbW, thumbH, Image.SCALE_SMOOTH);
return new ImageIcon(scaled);
}
This is the folder I used to test:
And the outputs with your code and mine:
Important notes
And as as a recommendation don't make a window that big if all you're using is that little bar above. If you're adding something else below, then it's ok but for now it's not that "user friendly" (IMHO). Instead of JFrame#setSize() you could try using JFrame#pack() method so your frame resizes to it's preferred size.
Some other things I noted in your program:
You're not placing it inside the Event Dispatch Thread (EDT) which is dangerous since your application won't be Thread safe that way. You can change that if you change your main method as follows:
public static void main(String argS[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
PVE pv = new PVE();
}
});
}
You're setting the JScrollPane preferred size, instead you should override its getPreferredSize() method, see Should I avoid the use of setPreferred|Maximum|MinimumSize methods in Java Swing? (YES)
You're extending JFrame, you should instead create an instance of it unless you're overriding one of its methods (and you're not, so don't do it) or you have any good reason to do it. If you need to extend a Container you should extend JPanel instead, as JFrame is a rigid container which cannot be placed inside another one. See this question and this one.
I think I'm not missing anything, and hope this helps
Your “scaled” images are actually images which are the same size as the original image, but are blank except for a scaled version drawn in the upper left corner. That upper left corner is clipped out of view in each rendered cell (at least for the somewhat large images I tested with).
The scaled image needs to be created with the thumbnail size, not the size of the original image. Meaning, change this:
BufferedImage bf = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
to this:
BufferedImage bf = new BufferedImage(thumbW, thumbH, BufferedImage.TYPE_INT_ARGB);

how to get the image of a Swing widget? [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Java Swing : Obtain Image of JFrame
I am working on a little drag-and-drop Java GUI builder. It works so far, but the widgets I'm dragging and dropping are just rectangles I'm dynamically drawing on a canvas.
If I have a rectangle that represents a widget like a JButton, is there a way for me to create a JButton, set the size and get the image of that JButton if it was drawn on the screen? Then I could paint the image to the screen instead of just my boring rectangle.
For example, I'm currently doing this to draw a (red) rectangle:
public void paint(Graphics graphics) {
int x = 100;
int y = 100;
int height = 100;
int width = 150;
graphics.setColor(Color.red);
graphics.drawRect(x, y, height, width);
}
How can I do something like:
public void paint(Graphics graphics) {
int x = 100;
int y = 100;
int height = 100;
int width = 150;
JButton btn = new JButton();
btn.setLabel("btn1");
btn.setHeight(height); // or minHeight, or maxHeight, or preferredHeight, or whatever; swing is tricky ;)
btn.setWidth(width);
Image image = // get the image of what the button will look like on screen at size of 'height' and 'width'
drawImage(image, x, y, imageObserver);
}
Basically, you'll paint your component to an image, and then paint that image wherever you want. In this case it's okay to call paint directly because you're not painting to the screen (but to a memory location).
If you wanted to optimize your code more than I've done here, you can save the image, and just repaint it in a different location whenever it's moved (instead of calculating the image from the button every time the screen repaints).
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class MainPanel extends Box{
public MainPanel(){
super(BoxLayout.Y_AXIS);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
// Create image to paint button to
BufferedImage buttonImage = new BufferedImage(100, 150, BufferedImage.TYPE_INT_ARGB);
final Graphics g2d = buttonImage.getGraphics();
// Create button and paint it to your image
JButton button = new JButton("Click Me");
button.setSize(button.getPreferredSize());
button.paint(g2d);
// Draw image in desired location
g.drawImage(buttonImage, 100, 100, null);
}
public static void main(String[] args){
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MainPanel());
frame.pack();
frame.setSize(400, 300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}

Double Buffer a JFrame

I have been reading a lot about Double Buffering as I am working on a 2D game. I have come across many different strategies for implementation, but am unsure how Double Buffering would fit into the way I have created my game window. For example, one article I came across (http://content.gpwiki.org/index.php/Java:Tutorials:Double_Buffering) suggested having a separate method for drawing; however, I suspect this would be applicable if you were drawing shapes, instead of adding components to the window.
Here is my main GUI code (keylistener methods omitted)
public class MainWindow extends JFrame implements KeyListener{
private Dimension dim;
private CardLayout layout;
private JPanel panel;
private JLayeredPane gameLayers;
private Menu menu;
private MiniGame miniGame;
private Board board;
private Sprite sprite;
private Game game;
private Map map;
private GameState gs;
private Boolean[] keys;
public MainWindow(Game game, GameState gs, Map map, Sprite sprite){
//Call superclass.
super();
addKeyListener(this);
//Sore references to critical game components.
this.game = game;//So we can call methods when an event occurs.
this.gs = gs;
this.map = map;//Used to construct the board.
//The board needs to know the layout of the map.
this.sprite = sprite;//Used to add the sprite to one of the layers.
//Instantiate objects.
dim = new Dimension(800, 600);
layout = new CardLayout();
panel = new JPanel(layout);
menu = new Menu();
miniGame = new MiniGame();
board = new Board(map);
gameLayers = new JLayeredPane();
//Remove decoration and place window in center of screen.
setUndecorated(true);
Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
setBounds((screenDim.width /2)-(dim.width/2),
(screenDim.height/2)-(dim.height/2),
dim.width,
dim.height);
//Add the board to a layer.
gameLayers.add(board, JLayeredPane.DEFAULT_LAYER);
board.setBounds(0, 0, dim.width, dim.height);
board.setBoard();
//Add the sprite to a layer.
gameLayers.add(sprite, JLayeredPane.PALETTE_LAYER);
sprite.setBounds(0, 0, 50, 50);
//Add components to window.
panel.add(gameLayers, "gameLayers");
panel.add(miniGame, "miniGame");
panel.add(menu, "menu");
//Add the "cards" to the window.
add(panel);
//JFrame housekeeping.
pack();
setSize(dim);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
setVisible(true);
//Holds state when an event is triggered.
//Ugly hack to circumvent delay issue.
keys = new Boolean[4];
for(int i=0; i<keys.length; i++){
keys[i] = false;
}
}
}
How would you recommend I approach this? Bearing in mind that the Board is a JPanel consisting of a grid of scaled images, and the sprite will be a JComponent displaying a scaled image.
Regards,
Jack.
Override the JPanel's paintComponent() Method and paint the content into a BufferedImage image first. Once done, copy the content of the BufferedImage into the graphics context you get from paintComponent().
protected void paintComponent(Graphics g)
{
BufferedImage bufferedImage = new BufferedImage(500, 500, BufferedImage.TYPE_ARGB);
Graphics2D g2d = bufferedImage.createGraphics();
//paint using g2d ...
Graphics2D g2dComponent = (Graphics2D) g;
g2dComponent.drawImage(bufferedImage, null, 0, 0);
}
As the Java Graphics Library is not fast, either well functional, you should inform yourself about the 'Lightweight Java Game Library' ( http://lwjgl.org/ ). It uses OpenGL, a strong Graphics Library, using native code.
Lwjgl is also used for the game Minecraft.
Also, OpenGL is used for different languages, so you could learn multi-functional and high-level programming.

Categories