I want to change the look of a JScrollBar.
I do this with overwriting/extending ScrollBarUI.
It´s no problem to change the outlook of the arrowbuttons by overwriting createIncreaseButton and createDecreaseButton.
I change the width of the track by overwriting paintThumb and paintTrack Methods.
It looks now like <----o----> (a very thin trackline and an oval thumb/knob).
PROBLEM:
The knob can't move till the very end:
What it does look like: <---o------>
What it should look like: <---------o>
I know this is because I made the oval not stretching (the original rectangle stretches with the width).
I'm totally clueless as were to change the computing of the thumb move so it can move until the end.
I would be very thankful for help.
Heres the code:
public class TestScrollBarMain extends JFrame {
public TestScrollBarMain() {
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
JPanel p = new JPanel();
p.setPreferredSize(new Dimension(500, 500));
JScrollPane s = new JScrollPane(p);
MyScrollBar b = new MyScrollBar();
s.setVerticalScrollBar(b);
getContentPane().add(s);
setSize(100, 100);
setVisible(true);
}
public static void main(String[] args) {
new TestScrollBarMain();
}
public class MyScrollBarUI extends BasicScrollBarUI {
#Override
protected void paintThumb(final Graphics g, final JComponent c, final Rectangle thumbBounds) {
if (thumbBounds.isEmpty() || !this.scrollbar.isEnabled()) {
return;
}
g.translate(thumbBounds.x, thumbBounds.y);
g.setColor(this.thumbDarkShadowColor);
g.drawOval(2, 0, 14, 14);
g.setColor(this.thumbColor);
g.fillOval(2, 0, 14, 14);
g.setColor(this.thumbHighlightColor);
g.setColor(this.thumbLightShadowColor);
g.translate(-thumbBounds.x, -thumbBounds.y);
}
#Override
protected void paintTrack(final Graphics g, final JComponent c, final Rectangle trackBounds) {
g.setColor(Color.black);
g.fillRect(trackBounds.width / 2, trackBounds.y, 3, trackBounds.height);
if (this.trackHighlight == BasicScrollBarUI.DECREASE_HIGHLIGHT) {
this.paintDecreaseHighlight(g);
} else if (this.trackHighlight == BasicScrollBarUI.INCREASE_HIGHLIGHT) {
this.paintIncreaseHighlight(g);
}
}
}
public class MyScrollBar extends JScrollBar {
MyScrollBar() {
super();
setUI(new MyScrollBarUI());
}
}
}
Include this on your MyScrollBarUI code:
protected void setThumbBounds(int x, int y,int width,int height)
{
super.setThumbBounds(x, y, 14, 14);
}
protected Rectangle getThumbBounds()
{
return new Rectangle(super.getThumbBounds().x,super.getThumbBounds().y,14,14);
}
protected Dimension getMinimumThumbSize()
{
return new Dimension(14,14);
}
protected Dimension getMaximumThumbSize()
{
return new Dimension(14,14);
}
Related
Huy guys, I have a weird problem.
I'm kinda new to swing and java applications.
I'm trying to make a custom UI jslider that changes a jlabel text when you move the thumb.
My problem is: when I use the addChangeListener(), it creates a weird glitch when moving the thumb.
If I don't use it, it works perfectly fine.
How can I update the JLabel without using the change listener or how can I fix this graphic bug?
Most of this code comes from stackoverflow since I don't know much about painting components.
See pictures at the button to better understand the problem
Thanks!
The code in my jpanel
JSlider slider = new JSlider(SwingConstants.HORIZONTAL, 1, 10, 1) {
#Override
public void updateUI() {
setUI(new CustomSliderUI(this));
}
};
// If I comment this line the visual glitch is gone when moving the thumb, but the value doesnt update
slider.addChangeListener((event) -> RAM_LABEL.setText(slider.getValue() + " Gb"));
slider.setMinorTickSpacing(1);
slider.setMajorTickSpacing(10);
slider.setSnapToTicks(true);
slider.setBounds(96, 317, 300, 35);
slider.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
slider.setOpaque(false);
this.add(slider);
The custom slider ui class
private static class CustomSliderUI extends BasicSliderUI
{
private static final int TRACK_HEIGHT = 8;
private static final int TRACK_ARC = 5;
private static final Dimension THUMB_SIZE = new Dimension(22, 20);
private final RoundRectangle2D.Float trackShape = new RoundRectangle2D.Float();
private final Image knob;
public CustomSliderUI(final JSlider b)
{
super(b);
knob = Swinger.getResource("knob.png");
}
#Override
protected void calculateTrackRect() {
super.calculateTrackRect();
trackRect.y = trackRect.y + (trackRect.height - TRACK_HEIGHT) / 2;
trackRect.height = TRACK_HEIGHT;
trackShape.setRoundRect(trackRect.x, trackRect.y, trackRect.width, trackRect.height, TRACK_ARC, TRACK_ARC);
}
#Override
protected void calculateThumbLocation() {
super.calculateThumbLocation();
thumbRect.y = trackRect.y + (trackRect.height - thumbRect.height) / 2;
}
#Override
protected Dimension getThumbSize() {
return THUMB_SIZE;
}
#Override
public void paint(final Graphics g, final JComponent c) {
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
super.paint(g, c);
}
#Override
public void paintTrack(final Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Shape clip = g2.getClip();
boolean inverted = slider.getInverted();
// Paint shadow.
g2.setColor(new Color(170, 170 ,170));
g2.fill(trackShape);
// Paint track background.
g2.setColor(new Color(200, 200 ,200));
g2.setClip(trackShape);
trackShape.y += 1;
g2.fill(trackShape);
trackShape.y = trackRect.y;
g2.setClip(clip);
// Paint selected track.
boolean ltr = slider.getComponentOrientation().isLeftToRight();
if (ltr) inverted = !inverted;
int thumbPos = thumbRect.x + thumbRect.width / 2;
if (inverted) {
g2.clipRect(0, 0, thumbPos, slider.getHeight());
} else {
g2.clipRect(thumbPos, 0, slider.getWidth() - thumbPos, slider.getHeight());
}
g2.setColor(Swinger.getTransparentWhite(0));
g2.fill(trackShape);
g2.setClip(clip);
}
#Override
public void paintThumb(final Graphics g)
{
g.drawImage(knob, thumbRect.x, thumbRect.y, null);
}
#Override
public void paintFocus(final Graphics g) {}
}
Visual glitch when you are moving the cursor, as soon as you stop pressing the mouse it goes back to normal
Regular cursor / when I move it without the change listener
Solved. I went with drawing my own background it was simplier.
private static class CustomSliderUI extends BasicSliderUI
{
private static final Dimension THUMB_SIZE = new Dimension(22, 20);
private final Image thumb, background;
private final JSlider slider;
public CustomSliderUI(final JSlider b)
{
super(b);
slider = b;
thumb = Swinger.getResource("thumb.png");
background = Swinger.getResource("slider.png");
}
#Override
protected Dimension getThumbSize() {
return THUMB_SIZE;
}
#Override
public void paintTrack(final Graphics g) {
g.drawImage(background, 10, 11, 280, 10, null);
}
#Override
public void paintThumb(final Graphics g)
{
g.drawImage(thumb, thumbRect.x, thumbRect.y, null);
slider.repaint();
}
#Override
public void paintFocus(final Graphics g) {}
}
JSlider slider = new JSlider(SwingConstants.HORIZONTAL, 1, 10, 1) {
#Override
public void updateUI() {
setUI(new CustomSliderUI(this));
}
};
slider.addChangeListener((event) -> RAM_LABEL.setText(slider.getValue() + " Gb"));
slider.setBounds(96, 317, 300, 35);
slider.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
slider.setOpaque(false);
this.add(slider);
I am having a problem about JScrollBar.
In my application I have 2 panels (one fixed, and one that changes depending on what the user chooses in the menu)
In a given panel I have a JScrollPane with a table. Since the standard java scrollbar was outside the theme of the application, I decided to try to create another one.
I basically create a JScrollPane and change its scrollBar to a custom one I created (scrollPane.setVerticalScrollBar (new CustomScrollBar ()) ;.
The first time I present the panel, the scrollbar is perfect. However, when I change to another panel and go back to it, the scrollbar model has reset.
What could this be/how do I solve it?
Creation JScrollPane code:
JScrollPane tablePanel = new JScrollPane(table);
tablePanel.setBounds(10, 148, 495, 200);
tablePanel.setBorder(new EmptyBorder(0, 0, 0, 0));
tablePanel.setBackground(Color.WHITE);
tablePanel.setVerticalScrollBar(new CustomScrollBar());
add(tablePanel);
CustomScrollBar Code:
public class CustomScrollBar extends JScrollBar {
public CustomScrollBar() {
setOpaque(false);
setUI(new BasicScrollBarUI() {
private final Dimension d = new Dimension();
#Override
protected JButton createDecreaseButton(int orientation) {
return new JButton() {
#Override
public Dimension getPreferredSize() {
return d;
}
};
}
#Override
protected JButton createIncreaseButton(int orientation) {
return new JButton() {
#Override
public Dimension getPreferredSize() {
return d;
}
};
}
#Override
protected void paintTrack(Graphics g, JComponent c, Rectangle r) {
}
#Override
protected void paintThumb(Graphics g, JComponent c, Rectangle r) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Color color = null;
JScrollBar sb = (JScrollBar) c;
if (!sb.isEnabled() || r.width > r.height) {
return;
} else if (isDragging) {
color = Colors.superdarkPurple;
} else if (isThumbRollover()) {
color = Colors.lightPurple;
} else {
color = Colors.darkPurple;
}
g2.setPaint(color);
g2.fillRoundRect(r.x, r.y, r.width, r.height, 10, 10);
g2.setPaint(Color.WHITE);
g2.drawRoundRect(r.x, r.y, r.width, r.height, 10, 10);
g2.dispose();
}
#Override
protected void setThumbBounds(int x, int y, int width, int height) {
super.setThumbBounds(x, y, width, height);
scrollbar.repaint();
}
});
}
public JScrollBar geCustomScrollBar() {
return this;
}
EDIT 1
This goes to a panel to add questions
public void gotoAddQuestionsPanel(Question q) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
currentQuestionsPanel = "add";
updateFrameComponentTreeUI();
remove(subPanel);
if (q != null) {
addQuestionsPanel.setQuestion(q);
}
subPanel = addQuestionsPanel.getPanel();
subPanel.setBackground(Color.WHITE);
subPanel.setBounds(304, 0, 515, 415);
getContentPane().add(subPanel);
subPanel.setLayout(null);
}
});
}
And this goes back to what has the customized ScrollBar
public void gotoQueryQuestionsPanel() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
currentQuestionsPanel = "query";
updateFrameComponentTreeUI();
remove(subPanel);
subPanel = queryQuestionsPanel.getPanel();
subPanel.setBackground(Color.WHITE);
subPanel.setBounds(304, 0, 515, 415);
getContentPane().add(subPanel);
subPanel.setLayout(null);
}
});
}
public void updateFrameComponentTreeUI() {
SwingUtilities.updateComponentTreeUI(this);
}
I want to have a JComponent on my JFrame, that has a custom shape in form of a polygon. Now i want to add a background image with colors in the same shape and blank color in the rest.
Is there a way to achieve this?
I have this test class:
public class Test extends JButton {
private final Polygon shape;
private final int provinceId;
private ImageIcon img;
public Test(Polygon p, int x, int y, int w, int h, int id, ImageIcon img) {
this.shape = p;
this.provinceId = id;
this.img = img;
setSize(w, h);
setLocation(x, y);
setIcon(img);
setContentAreaFilled(false);
addMouseListener(animation());
}
private MouseListener animation() {
return new MouseListener() {
public void mouseEntered(MouseEvent e) {
System.out.println("in");
}
public void mouseExited(MouseEvent e) {
System.out.println("out");
}
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
};
}
protected void paintComponent(Graphics g) {
g.drawPolygon(this.shape);
}
protected void paintBorder(Graphics g) {
g.drawPolygon(this.shape);
}
public boolean contains(int x, int y) {
return this.shape.contains(x, y);
}
public boolean isOpaque() {
return false;
}
public int getId() {
return this.provinceId;
}
public static void main(String[] args) {
JFrame f = new JFrame();
//Polygon p = new Polygon(new int[] {0, 400, 400, 0}, new int[] {0, 0, 300, 300}, 4);
Polygon p = new Polygon(new int[] {50, 150, 250, 350, 200, 50}, new int[] {0, 0, 50, 200, 300, 200}, 6);
ImageIcon ico = new ImageIcon("gfx/test.png");
Test t = new Test(p, 20, 20, 400, 300, 101, ico);
f.getContentPane().add(t);
f.setSize(500, 400);
f.setLayout(null);
f.setVisible(true);
}
}
but i only get this output: output
My original picture was: wanted output
You can do so by overriding the contains(Point p) method to only return true when p is in the bounds of your custom shape.
Then you best override isOpaque() to return false.
And finally you override paintComponent(Graphics g) to paint your component in whatever way you like (e.g. a background image with colors in the shape and blank color in the rest).
Sample code:
JPanel panel = new JPanel()
{
#Override
public boolean isOpaque()
{
return false;
}
#Override
public boolean contains(Point p)
{
// Use something that fits your shape here.
return p.getX() % 2 == 0;
}
#Override
public void paintComponent(Graphics g)
{
// do some painting
}
};
I want to paint a circle at the middle of JButton. Here is what I tried:
JButton jButton = new JButton(new CircleIcon());
public class CircleIcon implements Icon{
#Override
public void paintIcon(Component c, Graphics g, int x, int y) {
g.drawOval(10, 10, 20, 20);
}
#Override
public int getIconWidth() {
return 10;
}
#Override
public int getIconHeight() {
return 10;
}
}
I got this:
But I need something like this:
My question is what is the quare in the middle of the button on the first picture? And how to make it as in the second one?
The Swing tutorial on How to Use Icons should help: Creating a Custom Icon Implementation
import java.awt.*;
import javax.swing.*;
public class CircleIconTest {
public JComponent makeUI() {
JPanel p = new JPanel();
p.add(new JButton(new CircleIcon()));
return p;
}
public static void main(String... args) {
EventQueue.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new CircleIconTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
class CircleIcon implements Icon {
#Override
public void paintIcon(Component c, Graphics g, int x, int y) {
//g.drawOval(10, 10, 20, 20);
Graphics2D g2 = (Graphics2D) g.create();
//Draw the icon at the specified x, y location:
g2.drawOval(x, y, getIconWidth() - 1, getIconHeight() - 1);
//or
//g2.translate(x, y);
//g2.drawOval(0, 0, getIconWidth() - 1, getIconHeight() - 1);
g2.dispose();
}
#Override
public int getIconWidth() {
return 20;
}
#Override
public int getIconHeight() {
return 20;
}
}
what is the quare in the middle of the button on the first picture?
You have probably painted a rectangle over your codes. You should just look for drawRectangle( code line on your code block.
how to make it as in the second one?
There are 2 possible solution for it.
1 - You can set some size for the button. Because it seems need to get bigger to be seen like the latter picture. Try this
jButton.setPreferredSize(new Dimension(40, 40));
2 - You are using static values to draw a circle. I would use dynamic values for it. just like this.
JButton JButton = new JButton() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int nGap = 10;
int nXPosition = nGap;
int nYPosition = nGap;
int nWidth = getWidth() - nGap * 2;
int nHeight = getHeight() - nGap * 2;
g.setColor(Color.RED);
g.drawOval(nXPosition, nYPosition, nWidth, nHeight);
g.fillOval(nXPosition, nYPosition, nWidth, nHeight);
}
};
JButton.setHorizontalAlignment(JLabel.CENTER);
JButton.setVerticalAlignment(JLabel.CENTER);
This is the button display at different sizes.
jButton.setFocusPainted(false); // This will prevent the square highlight on focus!
hi i'm triyng to do something like this example
but i'm always getting the cross or in top-west or it doesn't appear and don't know why. I try to see the borderLayout and some stackoverflow explanations examples but didn´t find anything related. can someone explain to me what i'm doing wrong and why please?
public Base() {
super("Menu");
JPanel p = createPanel();
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
setSize(screen.width, screen.height);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
add(p);
}
private JPanel createPanel() {
JPanel P = new JPanel() {
public void paint(Graphics g) {
super.paint(g);
Graphic gr = new Graphicimpl();
g.drawLine(gr.PositionX(-25.0), gr.PositionY(0.0), gr.PositionX(25.0), gr.PositionY(0.0));
g.drawLine(gr.PositionX(0.0), gr.PositionY(25.0), gr.PositionX(0.0), gr.PositionY(-25.0));
}
};
//P.setSize(50, 50);
//P.setBorder(BorderFactory.createEmptyBorder(300, 300, 300, 300));
return P;
}
}
public class Graphicimpl implements Graphic{
int FACTOr_ESCALACION = 10;
public int PositionX(Double x) {
return (int) ((x * FACTOr_ESCALACION) + 320);
}
#Override
public int PositionY(Double y) {
return (int) ( - (y * FACTOr_ESCALACION ) +240);
}
}
public interface Graphic {
int PositionX(Double x);
int PositionY(Double y);
}
public class Main {
public static void main(String args[]) {
Base base=new Base();
}
}
The location of the cross depends on the coordinates you have inserted. Since you are inserting them manually. You can test the program with different coordinates until the cross shows where you want it to.