I am looking for a way to change the graphics of a component on a JMenuBar
I have the following JMenuBar.
package GUIMain;
import javax.swing.*;
import java.awt.*;
public class MyMenuBar extends JMenuBar
{
int fontMetrics;
FontMetrics fM;
JLabel lblSmartSize = new JLabel("", SwingConstants.CENTER);
JCheckBox chkbtnSmartSize = new JCheckBox();
SortsGui sG;
public MyMenuBar(SortsGui sG)
{
this.sG = sG;
setBorderPainted(true);
makePopUpMenu();
}
void makePopUpMenu()
{
add(Box.createHorizontalGlue());
fM = lblSmartSize.getFontMetrics(lblSmartSize.getFont());
fontMetrics = fM.stringWidth("Enable Smart Resizing?");
lblSmartSize.setMinimumSize(new Dimension(fontMetrics+10,25));
lblSmartSize.setPreferredSize(new Dimension(fontMetrics+10,25));
lblSmartSize.setMaximumSize(new Dimension(fontMetrics+10,25));
add(lblSmartSize);
chkbtnSmartSize.setBackground(lblSmartSize.getBackground());
add(chkbtnSmartSize);
}
}
This creates a JMenuBar which looks like this (apologies for blown up screenshot)
As you can see the JMenuBar has a JLabel and a JCheckBox on it. How would I change the background of the JCheckBox so that it does not have a square around it which is different to the standard look of the JMenuBar.
I have tried the following code and have so far been unsuccessful
chkbtnSmartSize.setBackground(this.getBackground());
(On a different attempt)
chkbtnSmartSize.setBackground(lblSmartSize.getBackground());
Any help in accomplishing this would be grateful
Thanks,
Dan
It turns out there are a few ways to do this.
The simplest way to do this would to be to remove the border and the background of the component. For example with this check box I should do
chkbtnSmartSize.setOpaque(false);
chkbtnSmartSize.setContentAreaFilled(false);
chkbtnSmartSize.setBorder(null);
chkbtnSmartSize.setFocusable(false);
Another way would be to change the background of the JMenuBar and then do the same for the check box.
Color color = Color.red;
#Override //This Method changes the background colour of the JMenuBar
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(color);
g2d.fillRect(0, 0, getWidth() - 1, getHeight() - 1);
}
...
chkbtnSmartSize.setBackground(color);
If you remove the background of the check box and change the color of the JMenuBar you do not need the line of code chkbtnSmartSize.setBackground(color);
Finally if you set the background of the JComponent to the same color of the background of the JMenuBar it will have the same affect as the first method did.
Related
Hi i am a beginner in java, here I have my program, however, when I try resizing the panel my text just disappears?
Moreover, how can i draw a thick green line under my text which will stay under the text even when resizing, I am very clueless?
import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
public class Groovy
{
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame= new JFrame("Shearing Word Demo");
frame.setResizable(true);
frame.setSize(new Dimension(500,250));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Toolkit it=Toolkit.getDefaultToolkit();
Dimension d=it.getScreenSize();
int w=frame.getWidth(), h=frame.getHeight();
frame.setLocation(d.width/2-w/2, d.height/2-h/2);
frame.add(new JComponent(){
#Override public void paintComponent(Graphics g){
Graphics2D g2=(Graphics2D) g;
g2.setColor(Color.magenta);
g2.setFont(new Font("Comic Sans MS",Font.BOLD,44));
g2.drawString("Feeling Groovy!", 110,125 );
}
});
frame.setVisible(true);
}
});
}
}
how can i draw a thick green line under my text which will stay under the text even when resizing, I
If you do custom painting then the basic steps you need to follow would be something like:
get the FontMetrics of the Graphics object using the getFonTMetrics() method
get the rectangle of text using the getStringBounds(...) method
use the setStroke(...) method of the Graphics2D object to set the thickness of the line to paint
use the drawLine(...) method Graphics2D object to paint the line based on the location of the text and the information of the Rectangle from the string bounds
An easier solution for displaying text is to use a JLabel. Then you can set the Border of the label. Read the section from the Swing tutorial on How to Use Borders for more information.
Note when doing custom painting with a JComponent you are also responsible for clearing the background of the component. So the first painting in the method should be:
g2.setColor( getBackground() );
g2.fillRect(0, 0, getWidth(), getHeight());
Most people use a JPanel for custom painting then you can just use:
super.paintComponent(g);
to make sure the background is cleared.
I work with java and I want to make a translucent window (like a black with 80% alpha). The basis of my code is those in the following post: How to make a transparent JFrame but keep everything else the same?
The problem is that when I run my program, the window is translucent but as you may see on the following picture, the background color (magenta) appears only on the text, not on the white.
Even worse, when I choose a black with transparency Color(0,0,0,125) as drawing color, nothing appears on the screen.
Here is what I have so far :
public class DssWindow extends JFrame
{
/**
*
*/
private static final long serialVersionUID = 2455172975892566000L;
/**
*
*/
public DssWindow()
{
super("My frame");
setUndecorated(true);
setBackground(new Color(0,0,0,0));
setAlwaysOnTop(true);
JPanel contentPane = new JPanel()
{
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if(!(g instanceof Graphics2D))
{
return;
}
Graphics2D gr = (Graphics2D)g.create();
gr.setColor(new Color(255,0,255,200));
gr.fillRect(0, 0, getWidth(), getHeight());
}
};
contentPane.setOpaque(false);
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
contentPane.setPreferredSize(new Dimension(screen.width,screen.height));
setContentPane(contentPane);
pack();
}
}
Do someone knows/has a clue of what is the problem ?
I am working on Linux (may this is a part of the answer).
Thank you.
Ok, my problem is stated here: Java Window Translucency on Linux
Graphics drivers seems to be the cause of this behaviour.
The situation here is the following: I have a JFrame, in which I store a list of images. When the right-key is pressed, I display the next image in this fullscreen JFrame. I want a Exit JButton in the upper right corner of the screen, which is the problem. To achieve that, I create a new JPanel everytime the image is changed, remove the old JPanel from the frame, and add the JButton to the new JPanel. The issue is the following: when I start the program, the JButton is in the middle of the JFrame. Once I load the next Image by pressing the right key the JButton is on the right position. However, workarounds like calling the method to display the next Image fail. Even if I set the JButton invisible until the right key was pressed and the second image loaded, it still will be in the center of the screen instead of the upper right. The following code is used:
BufferedImage image = ImageIO.read(images.get(number));
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, null);
}
};
if (currentPanel != null) {
this.remove(currentPanel);
}
panel.setSize(Gallery.this.getSize());
currentPanel = this.add(panel);
jButton1.setBounds(Gallery.this.getWidth() - jButton1.getWidth(), 0, jButton1.getWidth(), jButton1.getHeight());
panel.add(jButton1);
currentPanel.repaint();
This code is executed once at startup. The JButton then is in the middle.
It is executed again when loading the next Image, JButton now is in correct position.
I already tried many things, like adding the JButton to the JFrame instead, setting JPanels layout to null (makes button invisible), repaint, pack, invalidate, nothing I try seems to work. Is anyone able to instruct Swing to place that JButton in the upper right corner of my JFrame? Thank you a lot!
After cleaning up the mess I programmed there, an easy solution proved to work:
I added a custom JPanel to the JFrame at startup and set a fixed width to the JButton. Here the JPanel:
public class ImagePanel extends javax.swing.JPanel {
Image image;
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
public ImagePanel() {
initComponents();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
}
I set a fixed width to the JButton and added it to that JPanel:
jButton1 = new JButton();
jButton1.setText("Exit");
imagePanel = new ImagePanel();
imagePanel.setSize(Gallery.this.getSize());
add(imagePanel);
imagePanel.add(jButton1);
jButton1.setBounds(Gallery.this.getWidth() - 50, 0, 50, 30);
jButton1.addActionListener((ActionEvent e) -> exit());
displayImage(0);
The displayImage method consists of these lines:
BufferedImage image = ImageIO.read(images.get(number));
imagePanel.setImage(image);
imagePanel.repaint();
I am a newb and am trying to get a line to draw with my xslider and yslider so it would create cross hairs on the canvas panel. I cannot figure this out. The idea is that when I push the "Show" button a circle is to appear centered on the crosshairs set by the sliders. I used internalframes to create the button location and canvas for the circle and sliders. I need lines connected to the sliders. I cannot change the coding as to how the sliders work in tandem, part of expectations. Please assist.
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
public class CircleViewer2 extends JPanel
{
//Variables
Ellipse2D.Double circle;
static Color FillColor = Color.blue;
static String ShowHideName = null;
static JSlider xSlider;
static JSlider xSlider2;
static JSlider ySlider;
static JSlider ySlider2;
//Creation of the circle utilizing Ellipse2D
public CircleViewer2(int radius)
{
circle = new Ellipse2D.Double(0, 0, radius, radius);
setOpaque(false);
}
//Setting PreferredSize
public Dimension getPreferredSize()
{
Rectangle bounds = circle.getBounds();
return new Dimension(bounds.width, bounds.height);
}
//Establishing parameters for Drawing the Circle Via Paint
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(FillColor);
g2.fill(circle);
}
public static void main(String[] args)
{
final JPanel center = new JPanel();
center.setLayout(null);
center.setPreferredSize(new Dimension(400,400));
ShowHideName = "Show";
final JButton ShowHideButton = new JButton(ShowHideName);
ShowHideButton.setPreferredSize(new Dimension(75, 25));
ShowHideButton.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
if (ShowHideName.equals("Show"))
{
int xCoord = xSlider.getValue();
System.out.println(xCoord);
int yCoord = ySlider.getValue();
System.out.println(yCoord);
CircleViewer2 component = new CircleViewer2(50);
component.setLocation(xCoord,yCoord);
component.setSize(component.getPreferredSize());
center.add(component);
ShowHideName = "Hide";
center.repaint();
}
else
{
ShowHideName = "Show";
center.removeAll();
center.updateUI();
}
ShowHideButton.setText(ShowHideName);
}
});
final JButton ColorButton = new JButton("Color");
ColorButton.setPreferredSize(new Dimension(75, 25));
ColorButton.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
FillColor = JColorChooser.showDialog(null, "Pick a Color", Color.blue);
}
});
JFrame frame = new JFrame();
JInternalFrame canvas = new JInternalFrame();
JInternalFrame buttonFrame = new JInternalFrame();
JPanel buttonPanel = new JPanel();
buttonPanel.add(ShowHideButton);
buttonPanel.add(ColorButton);
javax.swing.plaf.InternalFrameUI ifu= buttonFrame.getUI();
((javax.swing.plaf.basic.BasicInternalFrameUI)ifu).setNorthPane(null);
buttonFrame.setBounds(0, 500, 500, 200);
buttonFrame.add(buttonPanel, BorderLayout.CENTER);
buttonFrame.setVisible(true);
xSlider = new JSlider(SwingConstants.HORIZONTAL,0,380,10);
BoundedRangeModel xmodel = xSlider.getModel();
xSlider2 = new JSlider(SwingConstants.HORIZONTAL);
xSlider2.setModel(xmodel);
ySlider = new JSlider(SwingConstants.VERTICAL,0,350,10);
BoundedRangeModel ymodel = ySlider.getModel();
ySlider.setInverted(true);
ySlider2 = new JSlider(SwingConstants.VERTICAL);
ySlider2.setModel(ymodel);
ySlider2.setInverted(true);
canvas.add(center, BorderLayout.CENTER);
canvas.add(xSlider, BorderLayout.SOUTH);
canvas.add(xSlider2, BorderLayout.NORTH);
canvas.add(ySlider, BorderLayout.EAST);
canvas.add(ySlider2, BorderLayout.WEST);
canvas.setBounds(0, 0, 500, 550);
canvas.setVisible(true);
javax.swing.plaf.InternalFrameUI ifu2 = canvas.getUI();
((javax.swing.plaf.basic.BasicInternalFrameUI)ifu2).setNorthPane(null);
frame.add(canvas, BorderLayout.NORTH);
frame.add(buttonFrame, BorderLayout.SOUTH);
frame.setBounds(0, 0, 500, 530);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
This is not a good implementation of the problem. You can inherit the JFrame and make the code clearer, it's the common method to play with Swing components. Any way, Add a change Listener to your sliders and change the location of the Center Panel according to the Sliders Value.
Something like that:
xSlider.addChangeListener( e -> {
center.setLocation(new Point(xSlider.getValue(), (int) center.getLocation().getY());
});
and so on.
This is a good place to start with Java/Swing GUI best practices
Your code looks way more complex than it needs to be, and I would try to simplify it greatly. Some suggestions:
Get rid of all the JInternalFrames and use JPanels instead.
Create a JPanel, say called drawingPanel, that has its paintComponent(Graphics g) overridden and perhaps its getPreferredSize() overridden, place this JPanel BorderLayout.CENTER in your main GUI.
In the paintComponent method, have the logic to draw the circles and the crosshairs based on fields of your class.
When a JSlider moves, have its ChangeListener change the state of the corresponding field, and then have it call repaint() on the drawing panel so that it will draw the changes.
When the show button is pressed, have it change the state of a boolean variable and then call repaint().
Have the drawingPanel use the boolean in its paintComponent method to decide whether or not to draw the filled circle.
Have the drawingPanel draw the lines in its paintComponent method based on the value returned by the JSliders. Again you're calling repaint in the JSlider's listeners, so the lines will move.
Do not add and remove components on button clicks since this adds unnecessary complexity which makes things much harder to code.
Don't move the center component or any component. Just use the fixed drawingPanel JPanel and move the location of the circle and the lines that it draws.
Since this is homework, I'm going to avoid posting code as the coding should be up to you. Much luck!
The idea of the program is that I have some buttons and an icon SOMEWHERE on the frame. I want the buttons to change the color. I'm only worried about making all the elements show up right now. If I comment out lines 11-13, I see "hello," printed out, with a red circle on top of it. Otherwise, I just have the button "red" without "hello" or my red circle. So here's my code:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
public class ButtonTester
{
public static void main (String[] args)
{
JFrame frame = new ButtonFrame();
frame.setLayout(new FlowLayout(FlowLayout.RIGHT));
JButton redButton = new JButton("Red");
frame.add(redButton);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class ButtonFrame extends JFrame
{
public static final int DEFAULT_WIDTH = 300;
public static final int DEFAULT_HEIGHT = 200;
public ButtonFrame()
{
setTitle("Hello");
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
ButtonPanel panel = new ButtonPanel();
add(panel);
}
}
class ButtonPanel extends JPanel
{
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawString("Hello !", 100, 100);
Icon ico = new ColorIcon(32);
ico.paintIcon(null, g, 75, 75);
}
}
I'm 90% sure the problem is lines 11-13, but I'm not sure what to change to make everything visible.
Your problem is that your ButtonPanel's size is 0. Have it override getPreferredSize() and you will see what I mean:
class ButtonPanel extends JPanel {
private static final int PREF_W = 150;
private static final int PREF_H = PREF_W;
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawString("Hello !", 100, 100);
// !! Icon ico = new ColorIcon(32);
// Icon ico = new ImageIcon();
// ico.paintIcon(null, g, 75, 75);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
Also as an unrelated aside, why are you creating an Icon inside of the paintComponent method? This doesn't make sense to me and would only serve to needlessly slow your graphics down.
Edit
You state:
Ok, I see the difference after overriding getPreferredSize() But what would be the "better" or "correct" way to create the icon? I'm just trying to follow the directions for an exercise out of a Java textbook: Exercise 4.14. Write a program that shows a frame with three buttons labeled "Red", "Green", and "Blue", and a label containing an icon showing a circle that is initially red. As the user clicks the buttons, the fill color of the circle should change. When you change the color, you need to invoke the repaint method on the label. The call to repaint ensures that the paintIcon method is called so that the icon can be repainted with the new color.
You need to think on this a different way. Myself I'd create three ImageIcons one for a blue circle, one for red, and one for green. I'd then display the ImageIcon in a JLabel on my JFrame. I'd change the color by simply swapping the label's icons via its setIcon(...) method. I wouldn't worry about futzing with paintComponent(...) but rather would try to solve this in as simple a fashion as possible.