BasicTabbedPaneUI paint html text - java

i would extend the BasicTabbedPaneUi so i can design my own tabPane. I have one problem with the html text, is to set the color of the text once the tab is selected. I override the paintText method with the following, almost the same code as the orignal method:
#Override
protected void paintText(Graphics g, int tabPlacement, Font font, FontMetrics metrics, int tabIndex, String title, Rectangle textRect, boolean isSelected) {
g.setFont(font);
View v = getTextViewForTab(tabIndex);
if (v != null) {
// html
Color fg = tabPane.getForegroundAt(tabIndex);
if (isSelected && (fg instanceof UIResource)) {
Color selectedFG = UIManager.getColor(
"TabbedPane.selectedForeground");
if (selectedFG != null) {
fg = selectedFG;
}
}
v.paint(g, textRect);
} else {
// plain text
int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex);
if (tabPane.isEnabled() && tabPane.isEnabledAt(tabIndex)) {
Color fg = tabPane.getForegroundAt(tabIndex);
if (isSelected && (fg instanceof UIResource)) {
Color selectedFG = UIManager.getColor(
"TabbedPane.selectedForeground");
if (selectedFG != null) {
fg = selectedFG;
}
}
g.setColor(fg);
SwingUtilities2.drawStringUnderlineCharAt(tabPane, g,
title, mnemIndex,
textRect.x, textRect.y + metrics.getAscent());
} else { // tab disabled
g.setColor(tabPane.getBackgroundAt(tabIndex).brighter());
SwingUtilities2.drawStringUnderlineCharAt(tabPane, g,
title, mnemIndex,
textRect.x, textRect.y + metrics.getAscent());
g.setColor(tabPane.getBackgroundAt(tabIndex).darker());
SwingUtilities2.drawStringUnderlineCharAt(tabPane, g,
title, mnemIndex,
textRect.x - 1, textRect.y + metrics.getAscent() - 1);
}
}
}
In the case we have html text for the tab, it v is not null. If i set a color to the graphics object used in the paint method it does not change the text color.
I use html because i want to have my tab's text on two lines.
Thanks for helping changing the color.

I would be reluctant to develop a custom TabbedPaneUI unless it were part of a complete Look & Feel implmentation.
Instead, consider a custom tab component, as shown in TabComponentsDemo and discussed in How to Use Tabbed Panes. This will give you absolute control over the component's appearance, without sacrificing compatibility with the user's chosen Look & Feel.

Related

How to keep rotating a FontAwesome-icon in Processing?

I'd like to keep rotating a icon from FontAwesome in Processing java. (the fa-spin icon to be precisely.) (\f110)
Link to effect: Example
My create-function for an icon
public void drawIcon(int size, String icon, float custom_height) {
font = createFont("fontawesome-webfont.ttf",size);
textFont(font);
if(icon != null && !icon.trim().isEmpty()) {
text(icon, width / 2, height / custom_height);
}
}
Initialization object + called method
To create my icon, I initialized an object and called my function in the draw()-method :
Content content = new Content(); // content object
PFont font; // font object
public void draw() {
content.drawIcon(46, "\uf110", 7);
}
I found the rotate/translate methods from the documentation, but can't figure out the correct parameters for rotating this icon 360 degrees continiously.
Attempt
public void draw() {
rotate(degrees(360));
content.drawIcon(46, "\uf110", 7);
}
I recommended loading the font once in setup() rather than potentially multiple times a second in drawIcon().
You can simply use text() after you've loaded the font and called textFont().
e.g.
PFont font; // font object
public void setup() {
font = loadFont("fontawesome-webfont.ttf",46);
textFont(font);
}
public void drawIcon(String icon, float custom_height) {
if(icon != null && !icon.trim().isEmpty()) {
text(icon, width / 2, height / custom_height);
}
}
In terms of rotating, at the moment you're specifying the same angle continuously. What you probably want to do is create a variable to keep track of the current angle, increment the angle and pass that to rotate() in draw().
PFont font; // font object
int angle = 0;
public void setup() {
font = loadFont("fontawesome-webfont.ttf",46);
textFont(font);
}
public void drawIcon(String icon, float custom_height) {
if(icon != null && !icon.trim().isEmpty()) {
text(icon, width / 2, height / custom_height);
}
}
public void draw() {
//increment angle (angle++; would to the same, but hopefully expanded version is easier to read)
angle = angle + 1;
rotate(degrees(angle));
content.drawIcon("\uf110", 7);
}
Be sure to checkout the Rotate Processing example as well.
You may notice that the symbol might not rotate from the centre.
This will require you to use multiple coordinate spaces using pushMatrix();/popMatrix(); calls. Do read the 2D transformations tutorial for more info on how to do that.

How do you embed a resizable JPanel inside of a JTextPane?

There are many questions of the converse, inserting a JTextPane into a JPanel. This is not my question. I need to be able to insert a custom JPanel (with drag and drop, drag, and mouse click listeners) into a JTextPane, which is then put into a JScrollPane, and finally put into a JFrame for displaying. The reason is because I need to have an image with support for resizing by dragging it within a chat client, which is itself primarily text.
Conveniently enough, there is a relevant method in JTextPane: insertComponent(Component c), but whenever I use it, my components end up being squished to exactly one line of text worth of space (even though they report having a larger size). This is perfect for plain buttons, but if I need anything larger, I'm out of luck. I can insert images by themselves just fine, with ImageIcons, but images wrapped inside a JPanel don't work at all (plus I can't add any listeners to ImageIcons, since they're not GUI elements; overriding one isn't an option).
Whenever a user drags an image into the chat client, this bit of code inserts the custom JPanel:
private void sendImage(BufferedImage im, int cl) throws IOException {
if(output == null) return;
//Send the image itself over to your friend
byte[] toSend = toBytes(im, cl);
sendString(nickname.hashCode() + "image"); //Header for image
output.writeInt(toSend.length); //Tells how many bytes to read.
output.write(toSend);
//Let the user know that the image was sent
float linmb = (float)(toSend.length / 1048576.0); //Size of file sent
addText("\n" + nickname + " sent an image! (" + linmb + " MB)\n", Color.RED.darker());
//Show the image itself
DraggerPanel d = new DraggerPanel(im, true);
text.insertComponent(d);
d.repaint();
//Spacer
addText("\n");
}
This is the source for DraggerPanel, the custom JPanel that holds an image:
public class DraggerPanel extends JPanel {
private BufferedImage image; //The image we're drawing
private Point startingPoint = null; //Starting point for resizing
private boolean first = true; //Is this the first drag?
private boolean lockedDrag; //If true, then lock x and y to be proportionally dragged.
public DraggerPanel(BufferedImage image, boolean lockedDrag) {
super();
this.image = image;
this.lockedDrag = lockedDrag;
//The listener for dragging events.
addMouseMotionListener(new MouseMotionListener() {
private int inWidth = 0, inHeight = 0; //Initial height and width values
private double ratio = 0; //Ratio of height to width for locked drag.
public void mouseDragged(MouseEvent m) {
if (first) { //If we're first, record initial position.
startingPoint = m.getPoint();
first = false;
inWidth = getWidth();
inHeight = getHeight();
ratio = (double)inHeight / inWidth;
} else { //Otherwise, change the size of the window.
if (!lockedDrag) {
int w = (int)startingPoint.getX() - m.getX();
int h = (int)startingPoint.getY() - m.getY();
setSize(Math.abs(inWidth - w), Math.abs(inHeight - h));
} else {
int w = (int)startingPoint.getX() - m.getX();
int h = (int)((double)ratio * w);
setSize(Math.abs(inWidth - w), Math.abs(inHeight - h));
}
}
repaint();
}
public void mouseMoved(MouseEvent m){
}
});
//Lets us know when you're not dragging anymore.
addMouseListener(new MouseAdapter(){public void mouseReleased(MouseEvent m){first = true;}});
//Set appropriate size.
if(image != null) setSize(image.getWidth(), image.getHeight());
else setSize(200,200);
//We're live, baby.
setVisible(true);
}
public void paint(Graphics g) {
if (image == null) super.paint(g);
else g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
}
}
Update 1: I followed #camickr 's advice, and updated the DraggerPanel to use setPreferredSize instead of setSize, as well as overrode paintComponent() instead of paint(). Now, the image has the proper height, but is stretched to the width of the JTextPane (which seems like what it was doing before). Furthermore, resizing doesn't seem to matter- the image doesn't change its size at all. Mouse events are definitely going through, but not affecting the size. It seems as though the original problem isn't fully resolved, since the JPanel's size isn't what I need it to be, and the solution to that will also lead to a solution to the resizing issue.
Update 2: I did it! I finally did it. To the future time travelers who have this issue, I basically yelled at the JTextPane by not only using setSize() in my overridden JPanel, but also setPreferredSize() and setMaximumSize(). The preferred one works well with height, and the maximum sets the width (God knows why). Thanks for your tips, #camickr!
my components end up being squished to exactly one line of text worth of space (even though they report having a larger size).
I would guess the size is not important.
I would think you need to override the getPreferredSize() method of your DraggerPanel to return the preferred size of the panel so the text pane can display the panel.
Also, custom painting is done by overriding the paintComponent(...) method NOT the paint() method.

Swing change foreground color of BasicArrowButton

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...)

Changing color of selected text in jTextPane

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;
}
};

JPanel in JTable gets focus on mouse click but not on mouse over

I have a table with one column containing JPanels. I have written the custom renderer and editor and they work fine. However, the panel contains a JLabel component with a tool tip. If I click into the cell and hover over the label the tool tip is displayed, but if I move the mouse into the cell and hover over the JLabel the tool tip wont display. I have added a mouse listener to the table as shown below where I get the Panel object and try to make it have focus.
public void mouseMoved(MouseEvent e) {
Point p = e.getPoint();
int row = table.rowAtPoint(p);
int column = table.columnAtPoint(p);
System.out.println(row + " " + column);
Object o = table.getModel().getValueAt(row, column);
if (o instanceof FileInfoCellPanel) {
FileInfoCellPanel ficp = (FileInfoCellPanel)o;
ficp.requestFocusInWindow();
//ficp.revalidate();
}
}
I am definitely getting the correct JPanel object but it never seems to get focus. So clicking in the cell seems to give focus to the panel but moving the mouse does not.
If you only want to display text in your tooltip, it is sufficient to set the tooltip on the component which you return by the renderer. This can be seen if you look at the implementation of the JTable#getTooltipText method, which I copied below
public String getToolTipText(MouseEvent event) {
String tip = null;
Point p = event.getPoint();
// Locate the renderer under the event location
int hitColumnIndex = columnAtPoint(p);
int hitRowIndex = rowAtPoint(p);
if ((hitColumnIndex != -1) && (hitRowIndex != -1)) {
TableCellRenderer renderer = getCellRenderer(hitRowIndex, hitColumnIndex);
Component component = prepareRenderer(renderer, hitRowIndex, hitColumnIndex);
// Now have to see if the component is a JComponent before
// getting the tip
if (component instanceof JComponent) {
// Convert the event to the renderer's coordinate system
Rectangle cellRect = getCellRect(hitRowIndex, hitColumnIndex, false);
p.translate(-cellRect.x, -cellRect.y);
MouseEvent newEvent = new MouseEvent(component, event.getID(),
event.getWhen(), event.getModifiers(),
p.x, p.y,
event.getXOnScreen(),
event.getYOnScreen(),
event.getClickCount(),
event.isPopupTrigger(),
MouseEvent.NOBUTTON);
tip = ((JComponent)component).getToolTipText(newEvent);
}
}
// No tip from the renderer get our own tip
if (tip == null)
tip = getToolTipText();
return tip;
}
As can be seen, to determine the tooltip text the renderer is asked for a component, and that component is asked for its tooltip text. Of course this only works for texts and not for e.g. images

Categories