How do I reduce the size of the JCheckBox icon? - java

I need to reduce the size of a JCheckBox item, which has no text. So far I tried to override the methods getPreferredSize() and getMaximumSize(). Also setting the Font size or the size of the JCheckBox itself doesn't evoke any changes. Is there a way to achieve this?

If you're talking about an Icon that is added to the JCheckBox, then best would be to create a new Icon from a new Image that is a resize of the original image. You can do this with a Image by calling the yourImage.getScaledInstance(...); method. Once you get the new image, create a new ImageIcon(newImage) and use it with your JCheckBox.
e.g.
Image oldImage = oldIcon.getImage();
Image newImage = oldImage.getScaledInstance(newWidth, newHeight,
Image.SCALE_DEFAULT);
Icon newIcon = new ImageIcon(newImage);
checkBox.setIcon(newIcon);

getPreferredSize and getMaximumSize only return the values assigned to preferredSize and maximumSize, respectively, for the JCheckBox object. If you want to change these values, use setPreferredSize and setMaximumSize instead:
jCheckBox.setPreferredSize(new Dimension(100, 300));
and/or:
jCheckBox.setMaximumSize(new Dimension(200, 600));

You can override the paint function like this:
final JCheckBox cb = new JCheckBox("",autoChangeTab) {
#Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.scale(.9, .9);
super.paint(g);
}
};

Related

Java swing + UI scale

I need to create an application with interface scaling. I have a button with icon inside and jpanel, that hold this button. The problem is that when scale is on - an icon is blurred and to fix this, I use downscaling in paintComponent. When system scale is on, I have normal image, as a result. But JPanel still have a scaled size. I tryed to override JPanel paintComponent too, but as a result I had too small buttons, because downscale on button and donwscale on JPanel work togeather. I can't use scale only from JPanel, when I click a button, it take a scaled size and image blurred again.
This is a simple example.
And the code is:
public class Test{
public static void main(String[] args) throws Exception{
System.setProperty("sun.java2d.uiScale", "1.5");
JFrame j = new JFrame();
Image img = ImageIO.read(new File("D:\\1.png"));
j.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
j.setPreferredSize(new Dimension(300, 150));
j.setVisible(true);
j.setLocationRelativeTo(null);
j.setLayout(new BorderLayout());
img = img.getScaledInstance((int) (60 * 1.5),(int) (60 * 1.5),Image.SCALE_DEFAULT);
JToggleButton tb = new JToggleButton(){
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.scale(0.67,0.67);
super.paintComponent(g2);
}
};
tb.setIcon(new ImageIcon(img));
JToggleButton tb2 = new JToggleButton(){
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.scale(0.67,0.67);
super.paintComponent(g2);
}
};
tb2.setIcon(new ImageIcon(img));
JPanel jPanel = new JPanel(){
};
jPanel.setLayout(new GridLayout(1,1));
jPanel.add(tb);
jPanel.setBackground(Color.RED);
JPanel content = new JPanel();
content.setLayout(new FlowLayout());
content.add(jPanel);
j.setContentPane(content);
j.pack();
}
}
I use java10.
Thank you.
You render your UI with scaling factor of 1.5: all UI including icons and images is scaled so that it displays correctly on a High DPI display. If image does not scale, it would be too small for a higher DPI setting.
If your application supports High DPI displays, i.e. UI scaling, you should provide images of different resolutions. See MultiResolutionImage in Java 9.
You can find sample code in this answer to a related question.

Simple way of scrolling over a certain rectangle with a JScrollPane and a JPanel (custom)

I have created a custom JPanel class called ImagePanel. I override the paintComponent method like this...
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image, 0,0, null);
}
The purpose of the custom panel is to simply draw an image.
In my JFrame, I create a ScollPane that is added to the JFrame. When I created the ScrollPane though, I pass in the instance of my imagePanel, like this...
ip = new ImagePanel();
JScrollPane jsp = new JScrollPane(ip);
this.add(jsp);
Now all I want as an easy to use way of using the scroll bars to scroll over my image. Right now the image is very large and scrollbars do not appear. I use the policy to make them visible, but the handles to the scrollbars are not there.
Does anyone know an easy way to do this?
Try with JPanel#setPreferredSize() that will force the JScrollPane to show the scroll bar if needed.
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image, 0,0, null);
// set the size of the panel based on image size
setPreferredSize(new Dimension(image.getWidth(), image.getHeight()));
}
EDIT
Setting setPreferredSize() inside overridden paintComponent() is not a good way.
You can do it in a simpler way using JLabel as suggested by #mKorbel. For more info have a look at the comments below.
BufferedImage image = ...
JLabel label = new JLabel(new ImageIcon(image)); // set the icon
JScrollPane jsp = new JScrollPane(label);
Screenshot:

Drawing a Component to BufferedImage causes display corruption

I am using the JScrollNavigator component described here, in order to provide a navigation window onto a large "canvas-like" CAD component I have embedded within a JScrollPane.
I have tried to adapt the JScrollNavigator to draw a thumbnail image of the canvas to provide some additional context to the user. However, the action of doing this causes the rendering of my application's main frame to become corrupted. Specifically, it is the action of calling paint(Graphics) on the viewport component (i.e. my main canvas), passing in the Graphics object created by the BufferedImage that causes subsequent display corruption; if I comment this line out everything works fine.
Below is the JScrollNavigator's overridden paintComponent method:
#Override
protected void paintComponent(Graphics g) {
Component view = jScrollPane.getViewport().getView();
BufferedImage img = new BufferedImage(view.getWidth(), view.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
// Paint JScrollPane view to off-screen image and then scale.
// It is this action that causes the display corruption!
view.paint(g2d);
g2d.drawImage(img, 0, 0, null);
Image scaled = img.getScaledInstance(getWidth(), getHeight(), 0);
super.paintComponent(g);
g.drawImage(scaled, 0, 0, null);
}
Does anyone have any suggestions as to the cause of the corruption? I would have thought that painting to an offscreen image should have no effect on existing paint operations.
EDIT
To provide some additional detail: The JScrollNavigator forms a sub-panel on the left-hand side of a JSplitPane. The JScrollPane associated with the navigator is on the right-hand side. The "corruption" causes the splitter to no longer be rendered and the scrollbars to not be visible (they appear white). If I resize the JFrame, the JMenu section also becomes white. If I attempt to use the navigator or interact with the scrollbars, they become visible, but the splitter remains white. It's as if the opaque settings of the various components has been affected by the rendering of the viewport view to an offscreen image.
Also, if I make the JScrollNavigator appear in a completely separate JDialog, everything works correctly.
EDIT 2
I can reproduce the problem consistently by doing the following:
Add a JMenuBar to the mFrame:
JMenuBar bar = new JMenuBar();
bar.add(new JMenu("File"));
mFrame.setJMenuBar(bar);
In the main() method of JScrollNavigator replace:
jsp.setViewportView(textArea);
... with:
jsp.setViewportView(new JPanel() {
{
setBackground(Color.GREEN);
setBorder(BorderFactory.createLineBorder(Color.BLACK, 5));
}
});
Ensure that the JScrollNavigator is embedded as a panel within mFrame, rather than appearing as a separate JDialog:
mFrame.add(jsp, BorderLayout.CENTER);
mFrame.add(nav, BorderLayout.NORTH);
Now when the application runs the JMenuBar is no longer visible; the act of painting the view (i.e. a green JPanel with thick black border) to the Graphics2D returned by BufferedImage.createGraphics() actually appears to be rendering it onscreen, possibly from the top-left corner of the JFrame, thus obscuring other components. This only seems to happen if a JPanel is used as the viewport view, and not another component such as JTextArea, JTable, etc.
EDIT 3
Looks like this person was having the same problem (no solution posted though): http://www.javaworld.com/community/node/2894/
EDIT 4
Here's the main and paintComponent methods that result in the reproducible error described in Edit 2:
public static void main(String[] args) {
JScrollPane jsp = new JScrollPane();
jsp.setViewportView(new JPanel() {
{
setBackground(Color.GREEN);
setBorder(BorderFactory.createLineBorder(Color.BLACK, 5));
}
});
JScrollNavigator nav = new JScrollNavigator();
nav.setJScrollPane(jsp);
JFrame mFrame = new JFrame();
JMenuBar bar = new JMenuBar();
bar.add(new JMenu("File"));
mFrame.setJMenuBar(bar);
mFrame.setTitle("JScrollNavigator Test");
mFrame.setSize(800, 600);
mFrame.setLayout(new GridLayout(1, 2));
mFrame.add(jsp);
mFrame.add(nav);
Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
mFrame.setLocation((screenDim.width - mFrame.getSize().width) / 2, (screenDim.height - mFrame.getSize().height) / 2);
mFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mFrame.setVisible(true);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Component view = jScrollPane.getViewport().getView();
if (img == null) {
GraphicsConfiguration gfConf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
img = new BufferedImage(view.getWidth(), view.getHeight(), BufferedImage.TYPE_INT_ARGB);
}
Graphics2D g2d = img.createGraphics();
view.paint(g2d);
Image scaled = img.getScaledInstance(getWidth(), getHeight(), 0);
g.drawImage(scaled, 0, 0, null);
}
EDIT 5
It seems like others are having trouble recreating the exact problem. I would ask people to run the code pasted here. When I first run this example I see the following:
Neither the JScrollNavigator or the JMenuBar have been painted; these frame areas are transparent.
After resizing I see the following:
The JMenuBar has still not been painted and it appears that the JPanel was at some point rendered at (0,0) (where the JMenuBar should be). The view.paint call within paintComponent is the direct cause of this.
Summary: The original JScrollNavigator uses the Swing opacity property to render a convenient green NavBox over a scaled thumbnail of the component in an adjacent JScrollPane. Because it extends JPanel, the (shared) UI delegate's use of opacity conflicts with that of the scrollable component. The images seen in edit 5 above typify the associated rendering artifact, also shown here. The solution is to let NavBox, JScrollNavigator and the scrollable component extend JComponent, as suggested in the second addendum below. Each component can then manage it's own properties individually.
I see no unusual rendering artifact with your code as posted on my platform, Mac OS X, Java 1.6. Sorry, I don't see any glaring portability violations.
A few probably irrelevant, but perhaps useful, observations.
Even if you use setSize(), appropriately in this case, you should still pack() the enclosing Window.
f.pack();
f.setSize(300, 200);
For convenience, add() forwards the component to the content pane.
f.add(nav, BorderLayout.WEST);
Prefer StringBuilder to StringBuffer.
Consider ComponentAdapter in place of ComponentListener.
Addendum: As suggested here, I got somewhat more flexible results using RenderingHints instead of getScaledInstance() as shown below. Adding a few icons makes it easier to see the disparate effect on images and text.
editPane.insertIcon(UIManager.getIcon("OptionPane.errorIcon"));
editPane.insertIcon(UIManager.getIcon("OptionPane.warningIcon"));
...
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Component view = jScrollPane.getViewport().getView();
BufferedImage img = new BufferedImage(view.getWidth(),
view.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D off = img.createGraphics();
off.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
off.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
view.paint(off);
Graphics2D on = (Graphics2D)g;
on.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
on.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
on.drawImage(img, 0, 0, getWidth(), getHeight(), null);
}
Addendum secundum: It looks like the JPanel UI delegate is not cooperating. One workaround is to extend JComponent so that you can control opacity. It's only slightly more work to manage the backgroundColor. NavBox and JScrollNavigator are also candidates for a similar treatment.
jsp.setViewportView(new JComponent() {
{
setBackground(Color.red);
setBorder(BorderFactory.createLineBorder(Color.BLACK, 16));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
});
I am also not sure what you mean by corruption, but I noticed that the resampled image is much nicer if you specify Image.SCALE_SMOOTH as the rescaling hint:
Image scaled = img.getScaledInstance(getWidth(), getHeight(), Image.SCALE_SMOOTH);
Maybe this is what you are looking for...
I was able to reproduce your problem and get you the result your looking for. The problem is that the drawing of the image wasn't complete by the time you were repainting again, so only portions of the image were being painted. To fix this, add this field to your JScrollNavigator class (as a lock):
/** Lock to prevent trying to repaint too many times */
private boolean blockRepaint = false;
When we repaint the component, this lock will be activated. It won't be released until we have been able to successfully paint the panel - then another paint can be executed.
The paintComponent needs to be changed to abide by the lock and use a ImageObserver when painting your navigation panel.
#Override
protected void paintComponent(final Graphics g) {
super.paintComponent(g);
if(!blockRepaint){
final Component view = (Component)jScrollPane.getViewport().getView();
BufferedImage img = new BufferedImage(view.getWidth(), view.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// Paint JScrollPane view to off-screen image and then scale.
// It is this action that causes the display corruption!
view.paint(g2d);
ImageObserver io = new ImageObserver() {
#Override
public boolean imageUpdate(Image img, int infoflags, int x, int y,int width, int height) {
boolean result = true;
g.drawImage(img, 0, 0, null);
if((infoflags & ImageObserver.FRAMEBITS) == ImageObserver.FRAMEBITS){
blockRepaint = false;
result = false;
}
return result;
}
};
Image scaled = img.getScaledInstance(getWidth(), getHeight(), 0);
blockRepaint = g.drawImage(scaled, 0, 0, io);
}
}

How to display an Image to component?

How to display an image to JPanel or to JLabel using the BufferedImage?
I load an Image using FileChooser and I need to display what I've loaded.
I don't extend my class to any container.
Override paintComponents(g) paintComponent(g) method of JPanel or JLabel and draw image in it. Something like follow:
JPanel panel = new JPanel(){
#Override
public void paintComponent(Graphics g) {
BufferedImage image = null; // get your buffered image.
Graphics2D graphics2d = (Graphics2D) g;
graphics2d.drawImage(image, 0, 0, null);
super.paintComponents(g);
}
};
Same thing for JLabel. Or in another way:
BufferedImage image = null; // get your buffered image.
ImageIcon icon = new ImageIcon((Image)image);
JLabel label = new JLabel();
label.setIcon(icon);
As you are saying that you are loading image from FileChooser it can be done in following
way:
ImageIcon icon = new ImageIcon(
fileChooser.getCurrentDirectory().toString()
+"/"+fileChooser.getSelectedFile().getName());
Now you can use ImageIcon in JLabel or add it in JPanel.
Above code is sample code and not tested so not necessary to run without error. You might need to change it as per your need.

How to set a transparent background of JPanel?

Can JPanels background be set to transparent?
My frame is has two JPanels:
Image Panel and
Feature Panel.
Feature Panel is overlapping Image Panel.
The Image Panel is working as a background and it loads image from a remote URL.
On Feature Panel I want to draw shapes. Now Image Panel cannot be seen due to Feature Panel's background color.
I need to make Feature Panel background transparent while still drawing its shapes and I want Image Panel to be visible (since it is doing tiling and cache function of images).
I'm using two JPanel's, because I need to seperate the image and shape drawing .
Is there a way the overlapping Jpanel have a transparent background?
Calling setOpaque(false) on the upper JPanel should work.
From your comment, it sounds like Swing painting may be broken somewhere -
First - you probably wanted to override paintComponent() rather than paint() in whatever component you have paint() overridden in.
Second - when you do override paintComponent(), you'll first want to call super.paintComponent() first to do all the default Swing painting stuff (of which honoring setOpaque() is one).
Example -
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TwoPanels {
public static void main(String[] args) {
JPanel p = new JPanel();
// setting layout to null so we can make panels overlap
p.setLayout(null);
CirclePanel topPanel = new CirclePanel();
// drawing should be in blue
topPanel.setForeground(Color.blue);
// background should be black, except it's not opaque, so
// background will not be drawn
topPanel.setBackground(Color.black);
// set opaque to false - background not drawn
topPanel.setOpaque(false);
topPanel.setBounds(50, 50, 100, 100);
// add topPanel - components paint in order added,
// so add topPanel first
p.add(topPanel);
CirclePanel bottomPanel = new CirclePanel();
// drawing in green
bottomPanel.setForeground(Color.green);
// background in cyan
bottomPanel.setBackground(Color.cyan);
// and it will show this time, because opaque is true
bottomPanel.setOpaque(true);
bottomPanel.setBounds(30, 30, 100, 100);
// add bottomPanel last...
p.add(bottomPanel);
// frame handling code...
JFrame f = new JFrame("Two Panels");
f.setContentPane(p);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 300);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
// Panel with a circle drawn on it.
private static class CirclePanel extends JPanel {
// This is Swing, so override paint*Component* - not paint
protected void paintComponent(Graphics g) {
// call super.paintComponent to get default Swing
// painting behavior (opaque honored, etc.)
super.paintComponent(g);
int x = 10;
int y = 10;
int width = getWidth() - 20;
int height = getHeight() - 20;
g.drawArc(x, y, width, height, 0, 360);
}
}
}
Alternatively, consider The Glass Pane, discussed in the article How to Use Root Panes. You could draw your "Feature" content in the glass pane's paintComponent() method.
Addendum: Working with the GlassPaneDemo, I added an image:
//Set up the content pane, where the "main GUI" lives.
frame.add(changeButton, BorderLayout.SOUTH);
frame.add(new JLabel(new ImageIcon("img.jpg")), BorderLayout.CENTER);
and altered the glass pane's paintComponent() method:
protected void paintComponent(Graphics g) {
if (point != null) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, 0.3f));
g2d.setColor(Color.yellow);
g2d.fillOval(point.x, point.y, 120, 60);
}
}
As noted here, Swing components must honor the opaque property; in this variation, the ImageIcon completely fills the BorderLayout.CENTER of the frame's default layout.
In my particular case it was easier to do this:
panel.setOpaque(true);
panel.setBackground(new Color(0,0,0,0,)): // any color with alpha 0 (in this case the color is black
(Feature Panel).setOpaque(false);
Hope this helps.
To set transparent you can set opaque of panel to false like
JPanel panel = new JPanel();
panel.setOpaque(false);
But to make it transculent use alpha property of color attribute like
JPanel panel = new JPanel();
panel.setBackground(new Color(0,0,0,125));
where last parameter of Color is for alpha and alpha value ranges between 0 and 255 where 0 is full transparent and 255 is fully opaque
public void paintComponent (Graphics g)
{
((Graphics2D) g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,0.0f)); // draw transparent background
super.paintComponent(g);
((Graphics2D) g).setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,1.0f)); // turn on opacity
g.setColor(Color.RED);
g.fillRect(20, 20, 500, 300);
}
I have tried to do it this way, but it is very flickery
As Thrasgod correctly showed in his answer, the best way is to use the paintComponent, but also if the case is to have a semi transparent JPanel (or any other component, really) and have something not transparent inside. You have to also override the paintChildren method and set the alfa value to 1.
In my case I extended the JPanel like that:
public class TransparentJPanel extends JPanel {
private float panelAlfa;
private float childrenAlfa;
public TransparentJPanel(float panelAlfa, float childrenAlfa) {
this.panelAlfa = panelAlfa;
this.childrenAlfa = childrenAlfa;
}
#Override
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(getBackground());
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, panelAlfa));
super.paintComponent(g2d);
}
#Override
protected void paintChildren(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(getBackground());
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setComposite(AlphaComposite.getInstance(
AlphaComposite.SRC_ATOP, childrenAlfa));
super.paintChildren(g);
}
//getter and setter
}
And in my project I only need to instantiate Jpanel jp = new TransparentJPanel(0.3f, 1.0f);, if I want only the Jpanel transparent.
You could, also, mess with the JPanel shape using g2d.fillRoundRect and g2d.drawRoundRect, but it's not in the scope of this question.

Categories