Is there anyway in Java SWT that I can place a label on top of another label and then have the label on top to have a transparent background?
I am doing this in a class that extends Composite as I want to create a custom SWT "fancy button" out of 2 labels. So the label below will be the lable that consist of only an image while the one on top will be the label with the text of the "fancy button". But the label on top has to have a transparent background so as to not cover the image below it.
Currently, the label on top is covering the label below.
Any idea how I could do this?
Thanks!
Instead you could try doing the following to get the same result.
Create a label
Assign an image to the label using a shell
Then use "setText()" to write something on the label.
The Text will appear above the image. You will be able to see the image.
( Showing only relavent code )
Example of Label with text/image.
Image image = new Image(display, "c:\\picture.jpeg");
Shell shell = new Shell(SWT.NO_TRIM);
shell.setBounds(10,10,200,200);
shell.setBackgroundImage(image);
shell.setBackgroundMode(SWT.INHERIT_DEFAULT);
Label label = new Label(shell, SWT.NONE);
label.setText("LAbel text here. ");
Since you want to make buttons.
You can use the same logic, using the "Button" api as well.
You can create a button with an image and then set any text above it.
( Showing only relavent code )
Example of Button
Button button = new Button(shell, SWT.PUSH);
button.setImage(image);
button.setText("Click Me");
I hope this is what you are trying to do.
instead of doing
drawString("text", x, y)
do
drawString("text", x, y, true)
it will make the background transparent, as per the documentation
Writing a text (as label) without background seems to be simple possible only in a Canvas using the GC class for the paint routine. I have written an inheritance of Canvas for that:
public class SwtTransparentLabel extends Canvas {
String text = "";
Font font = null;
public SwtTransparentLabel(Composite parent, int style) {
super(parent, style | SWT.TRANSPARENT);
addPaintListener(paintListener);
}
public void setText (String string) {
text = string;
}
public void setFont (Font font) {
this.font = font;
}
/**The listener for paint events. It is called whenever the window is shown newly. It does the work for graphic output. */
protected PaintListener paintListener = new PaintListener() {
#Override public void paintControl(PaintEvent e) {
GC gc = e.gc;
if(font !=null){ gc.setFont(font); }
//no: gc.setAlpha(100); //... experience, not necessary
gc.drawString(text, 0, 0, true);
}
};
}
That works similar as org.eclipse.swt.widgets.Label.
I am yet trying to improve the solution (setAlignment is missing). You may visit results on www.vishia.org/Java
Related
Can a set of lines be drawn on a text area component which would look like this .
I then need to be able to type in text over them . These lines also need to be erased and redrawn
Consider drawing lines on a Pane like so:
public class StageTest extends Application{
private static final double WIDTH = 100, HEIGHT = 60;
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("Test Stage");
Label label = new Label("Some text ");
label.setStyle("-fx-background-color:TRANSPARENT");
label.setAlignment(Pos.CENTER);
label.setPrefSize(WIDTH, HEIGHT);
Pane linesPane = getPane(label);
StackPane root = new StackPane(linesPane, label);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
private Pane getPane(Label label) {
Pane pane = new Pane();
pane.setStyle("-fx-background-color:WHITE");
Line blueLine = new Line();
blueLine.setStroke(Color.BLUE);
blueLine.startXProperty().bind(label.layoutXProperty());
blueLine.startYProperty().bind(label.layoutYProperty().add(label.heightProperty().multiply(.333)));
blueLine.endXProperty().bind(label.layoutXProperty().add(label.widthProperty()));
blueLine.endYProperty().bind(label.layoutYProperty().add(label.heightProperty().multiply(.333)));
Line redLine = new Line();
redLine.setStroke(Color.RED);
redLine.startXProperty().bind(label.layoutXProperty());
redLine.startYProperty().bind(label.layoutYProperty().add(label.heightProperty().multiply(.666)));
redLine.endXProperty().bind(label.layoutXProperty().add(label.widthProperty()));
redLine.endYProperty().bind(label.layoutYProperty().add(label.heightProperty().multiply(.666)));
pane.getChildren().addAll(blueLine, redLine);
return pane;
}
public static void main(String[] args) {
launch(args);
}
}
You may want to look at using the background property of TextArea.
new TextArea().setBackground(new Background(new BackgroundImage(myImage,BackgroundRepeat.NO_REPEAT,BackgroundRepeat.NO_REPEAT,BackgroundPosition.CENTER,BackgroundSize.DEFAULT)));
This code here is assuming you can get those lines as an image.
You can find more info for backgrounds here: https://docs.oracle.com/javase/8/javafx/api/javafx/scene/layout/Background.html
If you want the background image to change and be dynamic for your current needs, you have two options.
Just use a Canvas for the whole project. Paint the lines onto the canvas first, and then paint the letters on top of this. This could be better as it would allow you to customize your project to however you would like it, but it would take a bit more code and thinking to do.
Use the TextArea, and for the BackgroundImage, use a Snapshot of another Canvas. You can use a Canvas to draw the lines however you would like, and then convert it to an image using Snapshot.
WritableImage i = canvas.snapshot(new SnapshotParameters(), null);
Then, using this image, you can use that as the background of the TextArea by using BackgroundImage.
I didn't like the standard arrow button of the JComboBox, because it didn't fit well in my GUI. So I changed it. To do this, I wrote a class, which is extending BasicComboUI. In the regular case, everything is like I am expecting it. But as soon as I am disabling the button, it stays the way it is, which means that the button doesn't get the grey background color anymore. Instead, the left part of the list does. So I would like to know, if there is a way to define or to modify the disabling-behavior of the arrow button.
Here is my current code:
public class CustomArrowUI extends BasicComboBoxUI{
private static Color buttonBackground;
private static Color borderBox;
private static Color arrowColor;
private static Color buttonBorder;
public static ComboBoxUI createUI(JComponent c, Color buttonBackground, Color borderBox, Color arrowColor, Color buttonBorder)
{
CustomArrowUI.buttonBackground = buttonBackground;
CustomArrowUI.borderBox = borderBox;
CustomArrowUI.arrowColor = arrowColor;
CustomArrowUI.buttonBorder = buttonBorder;
return new CustomArrowUI();
}
#Override
protected JButton createArrowButton()
{
JButton button = new BasicArrowButton(BasicArrowButton.SOUTH, buttonBackground, borderBox, arrowColor, buttonBorder);
LineBorder border = new LineBorder(buttonBorder, 1);
button.setEnabled(false);
button.setBorder(border);
return button;
}}
What I could do is setting the background light grey as default, and change the color in the ActionListener of the previous button, which is enabling my JComboBox. But I kinda don't like this solution. I would prefer to do it directly in my CustomArrowUI
I found one short way to solve this. I added a ChangeListener to my arrow button, which is checking if the button is enabled or not, and coloring the button:
#Override
protected JButton createArrowButton()
{
final JButton button = new BasicArrowButton(BasicArrowButton.SOUTH, buttonBackground, borderBox, arrowColor, buttonBorder);
LineBorder border = new LineBorder(buttonBorder, 1);
button.setEnabled(false);
button.setBorder(border);
button.addChangeListener(new ChangeListener(){
#Override
public void stateChanged(ChangeEvent arg0) {
if(button.isEnabled())
button.setBackground(Color.WHITE);
else
{
button.setBackground(ColorPalette.LIGHT_GREY);
button.setBorder(new LineBorder(ColorPalette.LIGHT_GREY, 1));
}
}
});
return button;
}
Above I changed the background of the button and the border color too make it look like the arrow is part of the JComboBox, and not like a separate button inside of it.
Since the disabling-behavior is inheritet from the JComboBox itself (I guess), I don't need to take care if the button is usable or not. All I need to define is the color.
Another important point is to make sure, to call the setEnabled()-method after setting the UI of the JComboBox, if the JComboBox should be disabled by default. Otherwise it will not react initially, and the arrow button will look enabled.
I'm trying to create a mouseOver visual effect for several JLabel elements filled with text. The idea is to make each label darker when mouse enters and then return it to normal when the mouse leaves its area. Also all the labels are placed over a panel that has a background image.
Though simple enough, I've encountered a nasty behavior I can't overcome.
Bug 1: The first time I move mouse over a label it shows me the upper-left corner of my main window as its background.
Bug 2: Then, every time I move mouse over one label once, and then move it over the second label, the second one changes its background to the "summ background" (panel image + semitransparent background) of first label. Above that it seems that even the first label's text contents are being "copied" to the second label's background. This only happened once per label change: if I move mouse over the same label twice, the second mouse over event is painted correctly.
I've already tried to use MouseMotionListener, a different element (JButton), played with component modification methods and eve tried to override paint methods. No result.
I've attached an animated GIF showing the described behavior:
Two JLabels copying backgrounds and contents from each other
I'm relatively new to Swing so I'm not familiar with its caveats. Any idea what might cause this?
Custom Panel class:
public class ImagePanel extends JPanel{
private static final long serialVersionUID = -3995745756635082049L;
private Image image = null;
public ImagePanel(Image image){
this.image = image;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
if(image != null){
g.drawImage(image, 0, 0, this);
}
}
}
MouseListener class:
public class MouseHoverPiece implements MouseListener{
private static final Cursor CURSOR_HAND = new Cursor(Cursor.HAND_CURSOR);
private static final Cursor CURSOR_DEFAULT = new Cursor(Cursor.DEFAULT_CURSOR);
private static final Color HOVER_SHADOW = new Color(40, 80, 60, 50);
#Override
public void mouseEntered(MouseEvent e) {
JLabel component = (JLabel)e.getComponent();
component.setBackground(HOVER_SHADOW);
component.setCursor(CURSOR_HAND);
component.setOpaque(true);
component.repaint();
}
#Override
public void mouseExited(MouseEvent e) {
JLabel component = (JLabel)e.getComponent();
component.setBackground(null);
component.setCursor(CURSOR_DEFAULT);
component.setOpaque(false);
component.repaint();
}
MainWindow class:
Image background = ResourceLoader.loadImage("board.png");
ImagePanel panel = new ImagePanel(background);
panel.setBounds(10, 55, 480, 480);
panel.setLayout(null);
panel_main.add(panel);
final JLabel lblNewLabel1 = new JLabel("N");
lblNewLabel1.setHorizontalAlignment(SwingConstants.CENTER);
lblNewLabel1.setOpaque(false);
lblNewLabel1.setBounds(25, 24, 52, 52);
lblNewLabel1.setFont(lblNewLabel1.getFont().deriveFont(42f));
lblNewLabel1.addMouseListener(new MouseHoverPiece());
panel.add(lblNewLabel1);
final JLabel lblNewLabel2 = new JLabel("O");
lblNewLabel2.setHorizontalAlignment(SwingConstants.CENTER);
lblNewLabel2.setOpaque(false);
lblNewLabel2.setBounds(25+52+2, 24, 52, 52);
lblNewLabel2.setFont(lblNewLabel2.getFont().deriveFont(42f));
lblNewLabel2.addMouseListener(new MouseHoverPiece());
panel.add(lblNewLabel2);
private static final Color HOVER_SHADOW = new Color(40, 80, 60, 50);
Swing components have problems with transparent backgrounds because you are breaking the painting rules which state that an opaque component will completely paint the background.
Check out Backgrounds With Transparency for more information and a couple of solutions to the problem. You can either:
do custom painting on the label to manually paint the background
use a wrapper component and have that component do the painting for you.
I think I've found the solution. Both bugs had disappeared. What I did was to add parent container's (in my case the panel with the board background) repaint:
#Override
public void mouseEntered(MouseEvent e) {
JLabel component = (JLabel)e.getComponent();
component.setBackground(HOVER_SHADOW);
component.setCursor(CURSOR_HAND);
component.setOpaque(true);
Container container = component.getParent();
component.repaint();
container.repaint(); //fix
}
#Override
public void mouseExited(MouseEvent e) {
JLabel component = (JLabel)e.getComponent();
component.setBackground(null);
component.setCursor(CURSOR_DEFAULT);
component.setOpaque(false);
Container container = component.getParent();
component.repaint();
container.repaint(); //fix
}
Thanks everyone for your help ;)
I'm creating a text field in java using swing components. I want to make a search text field like one appears in Mozilla or other browsers.
I have added a button in text field. I have set border layout of JTextField. everything is working fine but whenever large text is written in text field (as it reaches the given size of text field) it goes behind the button. As everyone of you must have seen, this does not occur in search bars. Text must not go behind the button rather there must be some gap between button and text.
Does anyone know how to do that?
Maybe start with something like this:
The blinking cursor is positioned at the far right of the text field.
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
class ButtonsInTextField {
JPanel gui = new JPanel(new GridBagLayout());
JTextField textField;
ButtonsInTextField(int cols) {
JPanel textFieldWithButtonsPanel = new JPanel(new FlowLayout(
SwingConstants.LEADING, 5, 1));
textField = new JTextField(cols);
textFieldWithButtonsPanel.add(textField);
addButtonToPanel(textFieldWithButtonsPanel, 8);
addButtonToPanel(textFieldWithButtonsPanel, 16);
addButtonToPanel(textFieldWithButtonsPanel, 24);
// WARNING: Not sensitive to PLAF change!
textFieldWithButtonsPanel.setBackground(textField.getBackground());
textFieldWithButtonsPanel.setBorder(textField.getBorder());
textField.setBorder(null);
// END WARNING:
gui.add(textFieldWithButtonsPanel);
}
private final void addButtonToPanel(JPanel panel, int height) {
BufferedImage bi = new BufferedImage(
// find the size of an icon from the system,
// this is just a guess
24, height, BufferedImage.TYPE_INT_RGB);
JButton b = new JButton(new ImageIcon(bi));
b.setContentAreaFilled(false);
//b.setBorderPainted(false);
b.setMargin(new Insets(0,0,0,0));
panel.add(b);
}
public final JComponent getGui() {
return gui;
}
public final JTextField getField() {
return textField;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
ButtonsInTextField bitf = new ButtonsInTextField(20);
JOptionPane.showMessageDialog(null, bitf.getGui());
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
As people have noted above, it might have helped to see the code, especially the Layout manager.
However, you might try the following (if you haven't yet):
Call setColumns
http://docs.oracle.com/javase/7/docs/api/javax/swing/JTextField.html#setColumns(int)
Call setPreferredSize /setMaximumSize/setMinimumSize depending on your layout manager.
But I'd try to avoid this solution because it's pixel-level maintenance.
Regards
As an alternative solution you can use a Component Border, which allows you to use the button as a Border so it appears within the text field.
How do you resize a JButton at runtime so it adapts to the text given by setSize? I've done some searching and this is the code I've come up with so far. Could this be turned into a utility method?
FontMetrics metrics = getFontMetrics( font );
int width = metrics.stringWidth( string );
P.S: No layout manager is being used.
You need to use setPreferredSize() on the component. Then, to resize it, call setBounds().
I would probably subclass the button, and override the setText(String text) method to include the resizing code.
#Override
public void setText(String arg0) {
super.setText(arg0);
FontMetrics metrics = getFontMetrics(getFont());
int width = metrics.stringWidth( getText() );
int height = metrics.getHeight();
Dimension newDimension = new Dimension(width+40,height+10);
setPreferredSize(newDimension);
setBounds(new Rectangle(
getLocation(), getPreferredSize()));
}
For testing, I did this in the constructor of my new JButton subclass:
public ResizeToTextButton(String txt){
super(txt);
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
setText(JOptionPane.showInputDialog("Text"));
}
});
}
So, whenever I clicked on the button I could change the text and see if it resized properly.
I had the same problem, even when using a layout manager (BorderLayout). But in my case a simple call to layoutContainer() of the associated layout manager and then a repaint() on the JFrame was sufficient for changing the width of the button.
button1.setText("New Label that differs in width");
// button1 is inside the container horizontalBox
horizontalBox.getLayout().layoutContainer(horizontalBox);
repaint(); // on the containing JFrame