In JSpinner class, how would I change the foreground color of two BasicArrowButton(up and down) components?
the component.setForeground(<<a_color>>) doesn't work.
Thanks in advance.
EDIT
private void set_colors(JSpinner spinner){
int n = spinner.getComponentCount();
for (int i=0; i<n; i++)
{
Component c = spinner.getComponent(i);
System.out.println(c);
if (c instanceof BasicArrowButton)
{
c.setForeground(ds_conn_text.getForeground());//doesn't work, doesn't change arrow color
c.setBackground(ds_conn_text.getBackground());
BasicArrowButton c0=(BasicArrowButton) c;c0.setBorder(ok_button.getBorder());
}
}
}
This is a follow-up question of Swing change the JSpinner back and fore colors
It is not possible to only set the color of the arrows without overriding the paint method. The reason is simply that the color for the arrows is the same color as the color that is used for the "shadows" of the buttons. So you could put the line
UIManager.getDefaults().put("controlDkShadow", Color.MAGENTA);
somewhere into your main, but this would not only change the arrow colors, but also other elements' colors which actually should not be changed.
An ugly/hacky way to set this color only for a particular instance would be
private static void hackilySetColor(JSpinner spinner, Color color)
{
int n = spinner.getComponentCount();
for (int i=0; i<n; i++)
{
Component c = spinner.getComponent(i);
if (c instanceof BasicArrowButton)
{
try
{
Field field = BasicArrowButton.class.getDeclaredField("darkShadow");
field.setAccessible(true);
field.set(c, color);
field.setAccessible(false);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
but this uses reflection, is really an ugly hack, and still replaces the color of the "dark shadow" border of the buttons.
You'll be better off with an own UI for things like this (or ... just don't change the color at all - this seems rather useless for me anyhow...)
Related
I am trying to change the JCalendar component background color from the component properties itself with no success.
While changing the foreground color from the component proprieties is working fine.
I also tried menuCalendar.setBackground(new Color(135,239,251)) with no success.
Can anyone help?
Setting the background color for JCalendar is surprisingly complicated. There is one convenience method which allows to change part of the calendar's background. You could see if this does what you want first: menuCalendar.setDecorationBackgroundColor(new Color(135,239,251));
This probably won't do what you want. Changing the color of the background behind the day buttons and the colors of the buttons themselves can be changed with the following code. It has to be done this way as JCalendar uses native Swing components which are nested in one another and convenience methods seem to be lacking:
for (int i = 0; i < menuCalendar.getComponentCount(); i++) {
if (menuCalendar.getComponent(i) instanceof JDayChooser) {
JDayChooser chooser = ((JDayChooser) menuCalendar.getComponent( i ) );
JPanel panel = (JPanel) chooser.getComponent(0);
// the following line changes the color of the background behind the buttons
panel.setBackground(Color.BLACK);
// the for loop below changes the color of the buttons themselves
for (int y = 0; y < panel.getComponentCount(); y++) {
panel.getComponent(y).setBackground(Color.BLACK);
}
break; // leave the for loop, we're done
}
}
I'm finishing my homework in OOP Java. The assignment is to load images on a JFrame, be able to move them around (top layer should be prioritized, it is currently not) and click them to "flip them" (change the source of the image essentially). I'm currently having trouble finding a solution on how to properly "layer" images that are visible on the screen and to prioritize the images on the top first (currently the bottom ones are being prioritized).
I also have issues finding a good way to change the source of the images, as our teacher has prohibited extending the Picture class with Swing.
My first attempt at solving this was saving the information of every individual "Picture" object in an ArrayList. This works to save the position of the images but does not solve my issue with the layering. I also wanted to use JLayeredPane but as I found out, it was harder than I thought as I have yet to find a viable solution this way (I might be missing some obvious facts about how it works).
I'm thinking what probably needs to happen is that I save the "position" of each image in some type of Array, then using this array to print out the images via paintComponent # ImagePanel. This is currently what I am doing but it does not act as I wish it to. I think my way of loading in the images in the "Picture" class might have something to do with it. I don't have a lot of experience in Java so all of this is new to me.
I don't want to print out all of my codes as I have 4 classes, so I'm going to print out what I feel are the essential methods in each class. If there's something missing that you guys need in order to guide me in the right direction I'll provide that aswell.
draw # Picture
public void draw(Graphics g, int i) {
try {
BufferedImage img = ImageIO.read(new File("images/icon_"+ i +".gif"));
g.drawImage(img, x, y, null);
} catch(IOException ie) {
System.out.println("Could not find images");
}
}
mousePressed & mouseDragged # MouseHandler
public void mousePressed (MouseEvent e) {
Point point = e.getPoint();
chosen = imagepanel.locateImage(point);
}
public void mouseDragged (MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (chosen != null) {
imagepanel.moveImage(chosen, x, y);
}
}
loadImages & paintComponent # ImagePanel
private final static int IMAGES = 7;
private ArrayList <Picture> imageCollection = new ArrayList<>();
private Picture im;
Random rand = new Random();
public void loadImages() {
for(int i=0; i<IMAGES; i++) {
int x = rand.nextInt(400) + 40;
int y = rand.nextInt(400) + 60;
im = new Picture(x,y);
imageCollection.add(im);
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int i = 0;
for (Picture im : imageCollection) {
i++;
im.draw(g, i);
}
}
I expect the images to stack on top of eachother whenever "flipped" (clicked) or moved (dragged). They do not currently do this as they just maintain their "depth" position. I've tried implementing an Image[] without success.
I also have a flip method where I tried using setIcon (I was using ImageIcon instead of Image previously) but this did not really work for some reason.
I also would love for any feedback on the code so far and any improvements that could be made as I always want to improve.
EDIT: I manage to solve my problems, however I'm sure there's a better way to do this.
public void placeFirst(Picture im) {
int pos = imageCollection.indexOf(im);
imageCollection.remove(pos);
imageCollection.add(0, im);
}
public void flipImage(Picture im) {
im.flip();
placeFirst(im);
repaint();
}
public void moveImage(Picture im, Point point) {
im.move(point.x-(im.getWidth(im)/2), point.y-(im.getHeight(im)/2));
placeFirst(im);
repaint();
}
public Picture locateImage(Point point) {
for (int i=0; i<imageCollection.size(); i++) {
Picture im = imageCollection.get(i);
if (im.fits(point)) {
return im;
}
}
return null;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// There probably exists a better and visually nicer way of doing this
for (int i=imageCollection.size()-1; i>=0; i--) {
Picture im = imageCollection.get(i);
im.draw(g);
}
}
chosen = imagepanel.locateImage(point);
Well, we don't know how the locateImage(...) method works, but I would guess you just iterate through the array until you find a match.
So you will always find the same match.
So if you want an image to stack on top you have two issues:
you need to modify the search order so that when you click on an image you move it to position 0 in the ArrayList so it is always found first
but know when you paint images you need to paint images from the end of the ArrayList to the beginning, so the first image in the ArrayList gets painted last.
I am creating a text editor using a JTextPane that allows the user to change the color of selected text. But when the user selects the text, then chooses the option to change the color (say, to red) the text does not appear as red until the text is unselected. I tried using setSelectedTextColor to change the color of the selected text, but that doesn't work since that changes the text to red anytime text is selected afterwards. Is there a way to have selected text show up as it's actual color? Or like the way it works in Word where it's not the actual color of the text, but when text of different colors are selected they show up as different colors even when selected.
I use the following code to set up the JTextPane and button that changes the selected text to red:
JButton redButton = new JButton(new StyledEditorKit.ForegroundAction("red", Color.RED));
redButton.setFocusable(false);
buttonPanel.add(redButton);
The JTextPane is set up as with content type HTML and uses the HTMLEditorKit:
p=new JTextPane();
p.setSize(300, 300);
kit = new HTMLEditorKit();
p.setEditorKit(kit);
p.setDocument(kit.createDefaultDocument());
p.setContentType("text/html");
p.setEditable(true);
Let me know if you need more source code to understand the question. Thank You!
Take a look at the DefaultHighlightPainter inner class of DefaultHighlighter.
The method
public void paint(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c) {
Rectangle alloc = bounds.getBounds();
try {
// --- determine locations ---
TextUI mapper = c.getUI();
Rectangle p0 = mapper.modelToView(c, offs0);
Rectangle p1 = mapper.modelToView(c, offs1);
// --- render ---
Color color = getColor();
if (color == null) {
g.setColor(c.getSelectionColor());
}
else {
g.setColor(color);
}
As you can see it uses either getColor() or getSelectionColor(). You can extend the class and adapt the highlight painting.
Or use a simpler approach to override your JTextPane's getSelectionColor(). In the method just check whether text is selected and use attributes of selected elements to get desired ccolor. If nothing is selected just return super.getSelectedColor()
UPDATE:
Actually applying colors for selection is used on low level GlyphView's
public void paint(Graphics g, Shape a) {
...
JTextComponent tc = (JTextComponent) c;
Color selFG = tc.getSelectedTextColor();
if (// there's a highlighter (bug 4532590), and
(tc.getHighlighter() != null) &&
// selected text color is different from regular foreground
(selFG != null) && !selFG.equals(fg)) {
Highlighter.Highlight[] h = tc.getHighlighter().getHighlights();
if(h.length != 0) {
boolean initialized = false;
int viewSelectionCount = 0;
for (int i = 0; i < h.length; i++) {
Highlighter.Highlight highlight = h[i];
int hStart = highlight.getStartOffset();
int hEnd = highlight.getEndOffset();
if (hStart > p1 || hEnd < p0) {
// the selection is out of this view
continue;
}
if (!SwingUtilities2.useSelectedTextColor(highlight, tc)) {
continue;
}
...
As you can see applying selection color vs default color of the view is defined in the SwingUtilities2.useSelectedTextColor(highlight, tc)
In the sources http://kickjava.com/src/com/sun/java/swing/SwingUtilities2.java.htm
public static boolean useSelectedTextColor(Highlighter.Highlight JavaDoc h, JTextComponent JavaDoc c) {
Highlighter.HighlightPainter JavaDoc painter = h.getPainter();
String JavaDoc painterClass = painter.getClass().getName();
if (painterClass.indexOf("javax.swing.text.DefaultHighlighter") != 0 &&
painterClass.indexOf("com.sun.java.swing.plaf.windows.WindowsTextUI") != 0) {
return false;
}
try {
DefaultHighlighter.DefaultHighlightPainter JavaDoc defPainter =
(DefaultHighlighter.DefaultHighlightPainter JavaDoc) painter;
if (defPainter.getColor() != null &&
!defPainter.getColor().equals(c.getSelectionColor())) {
return false;
}
} catch (ClassCastException JavaDoc e) {
return false;
}
return true;
}
So using the color depends on L&F and painter. If you define your onw painter the color won't be used.
It sounds like you may be using something other than a font family name. I re-factored this example to use JTextPane and saw the expected result. As noted there, the actions require a font family name, e.g. the default or face=SansSerif, as specified by the FontFamilyAction class nested in StyledEditorKit.
JTextPane textPane = new JTextPane();
Simplest way to change the color of selected Text :
int start = textPane.getSelectionStart();
int end = textPane.getSelectionEnd();
int selectedLength = end - start;
StyleDocument style = pane.getStyledDocument();
//this give your attribute set of selected Text.
AttributeSet oldSet = style.getCharacterElement(end-1).getAttributes();
//StyleContext for creating attribute set
StyleContext sc = StyleContext.getDefaultStyleContext();
// Attribute set which contains new color with old attributes
AttributeSet s = sc.addAttribute(oldSet, StyleConstants.Foreground, Color.RED);
//This set the color of the Text
style.setCharacterAttributes(start, selectedLength, s, true);
Adding my view. This could be further simple then above approaches.
JEditorPane ep = new JEditorPane() {
#Override
public Color getSelectionColor() {
return COLOR_YOU_WANT;
}
#Override
public Color getSelectedTextColor() {
return COLOR_YOU_WANT;
}
};
I'm using Nimbus Look and Feel,
I know how to change for example, the tooltip color, by using this code:
UIManager.put("info", Color.white);
But how can I change the icons (minimize, maximize and close) to another icon/png file?
Here is the the key of the close button: InternalFrame:InternalFrameTitlePane:"InternalFrameTitlePane.closeButton"[Enabled].backgroundPainter
the same as info back there.
And here is the site with all Keys: http://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/_nimbusDefaults.html#primary
Looks like a ugly Hack, but works for me.
JComponent title = ((BasicInternalFrameUI)myInternalFrame.getUI()).getNorthPane();
for (int i = 0; i < title.getComponentCount(); i++) {
JComponent component = (JComponent)title.getComponent(i);
if(component instanceof JButton) {
JButton button = ((JButton)component);
if(button.getName() == null) continue;
if(button.getName().endsWith("closeButton")) {
button.setIcon(myIcon);
button.setSelectedIcon(myIcon);
button.setPressedIcon(myIcon);
}
if(button.getName().endsWith("maximizeButton")) {
...
}
if(button.getName().endsWith("iconifyButton")) {
...
}
}
}
I am trying to create a custom Label. I want to do something like markups on an Image
depending on what the user enters. I really don't know how to do it but I hope that you will know what I am trying to achieve here. What is the proper way to derive the Label class? This is my code.
class CustomLabel extends Label
{
List paths;
Image image;
public CustomLabel(Image img,List paths)
{
this.image = img;
this.paths = paths;
}
public void paint(Graphics g)
{
g.setColor(0x000000);
for (int i = 0; i < paths.size(); i++)
{
Path path = (Path)paths.getModel().getItemAt(i);
int firstLocX = path.discoveredNode.getX();
int firstLocY = path.discoveredNode.getY();
int secondLocX = path.nodeDiscovered.getX();
int secondLocY = path.nodeDiscovered.getY();
g.drawLine(firstLocX, firstLocY, secondLocX, secondLocY);
}
g.drawImage(image, 0, 0);
UIManager.getInstance().getLookAndFeel().drawLabel(g, this);
}
}
I hope you can help me with this.
Thanks,
You shouldn't use UIManager.getInstance().getLookAndFeel().drawLabel(g, this);
Since you want your drawing to appear on top you want the label to draw first and then have your code so the first line in the paint method should be super.paint(g) which will take care of that.
Your call to drawImage draws it at 0,0 which is always wrong. You should position drawing based on getX() and getY().
Having said that I don't see anything that warrants subclassing. If you just want to draw an emblem why not create a style that has an aligned image in its background with the given emblem. Then just conditionally assign the right UIID to the label.