Strange issue with JLabel HTML rendering - java

I have the following really simple code for creating a JLabel and adding it to a panel using a MigLayout layout manager:
MigLayout layout = new MigLayout();
JPanel panel = new JPanel(layout);
panel.setBackground(Color.GRAY);
JLabel label = new JLabel("<html><h3>Some Text</h3></html>");
panel.add(label, "growx,w 220!,h 40!,top");
This should render the label as transparent so that the panel background is visible behind the label - this is the behaviour we want.
However on some PCs the label is rendered with a solid white background - ie as if opaque=true has been set.
Curiously, this isn't a problem if the label text is not formatted using html.
JLabel label = new JLabel("Some text");
We are using BasicLabelUI as the UI delegate so I would expect to see standard painting behaviour here.
This is running using jre 1.6.0_30 in Windows XP. Has anyone seen something like this before? Could it be something to do with differences between the graphics hardware running on the various machines?

I've worked out what was happening after taking some time away from the problem.
It's to do with Stylesheets and HTMLEditorKit.
Assume the following sample css:
body {
background-color: #ffff00}
The following code simple loads this into an new HTMLEditorKit instance, then adds a non-opaque html label to a panel.
public class HTMLLabelTest extends JFrame {
public static void main(String[] args) throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
JFrame frame = new HTMLLabelTest();
frame.pack();
frame.setVisible(true);
}
});
}
public HTMLLabelTest() {
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
HTMLEditorKit htmlEditorKit = new HTMLEditorKit();
StyleSheet styleSheet = new StyleSheet();
URL resource = getClass().getResource("/stylesheet.css");
styleSheet.importStyleSheet(resource);
htmlEditorKit.setStyleSheet(styleSheet);
JLabel label = new JLabel();
label.setText("<html><B>Some HTML Formatted</B> text</html>");
label.setOpaque(false);
label.setHorizontalAlignment(JLabel.CENTER);
label.setHorizontalTextPosition(JLabel.CENTER);
label.setPreferredSize(new Dimension(30,20));
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(label);
panel.setOpaque(true);
panel.setBackground(Color.WHITE);
add(panel);
setPreferredSize(new Dimension(300,200));
}
}
Once imported, the stylesheet is made available to subsequent instances of HTMLEditorKit, such as the one being used to render the label. So in the code sample, the non-opaque label is shown with a yellow background.
If you create the label before installing the styles in the example, the label (and subsequent labels) will not pick up the style and be rendered non-opaque as desired.
The problem we have is that our application can be launched both separately and from within another app (running in the same jre). Some users of the second app have access to a screen that installs a stylesheet before our app can be launched. In these instances the styles are loaded and stored as defaults ready to be used by our app. This is why some users reported a problem and others didn't.
I haven't decided on the best solution for this yet. One possibility was to override the background style when creating the label html:
<html><body bgcolor=\"red\">Test</body></html>
However, if you use 'transparent' instead of a solid colour, the underlying colour from the stylesheet is shown instead. Annoying!

The fact JLabel hasn't been overriden is not relevant as all the painting is delegated to an instanceof ComponentUI, i.e. the look and feel. This will vary between environments.

Related

Java Swing JTextArea not displaying correctly

I am trying to use Java Swing to create a simple GUI in which I have a drawing pad and some buttons it all works fine until I add this code for the JTextField:
String text = "hello";
JTextArea textArea = new JTextArea(text);
textArea.setPreferredSize(new Dimension(500, 50));
textArea.setEditable(false);
Before adding this code the drawpad displays on the left of the screen followed by the buttons, when I add this only the drawpad is displayed unless I resize the frame in which case the buttons and text field reappear although the text field is hidden behind the drawpad slightly. Here is the full code:
public class testGUI extends Frame{
public static void main(String[] args) {
JFrame frame = new JFrame("Neural Networks");
frame.setSize(700, 300); //set the size of the frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true); //make it visible
Container content = frame.getContentPane();
content.setLayout(new BorderLayout());
JPanel mainPanel = new JPanel();
final PadDraw drawPad = new PadDraw();
drawPad.setSize(100, 100);
content.add(drawPad);
JButton clearButton = new JButton("Clear");
clearButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
drawPad.clear();
}
});
JButton loadButton = new JButton("Load");
loadButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
//Load something here
}
});
JButton testButton = new JButton("Test Draw Pad Image");
testButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
//
}
});
JButton loadImage = new JButton("Test image from file");
loadImage.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
//String filename = textField.getText();
}
});
String text = "hello";
JTextArea textArea = new JTextArea(text);
textArea.setPreferredSize(new Dimension(500, 50));
textArea.setEditable(false);
mainPanel.add(clearButton);
mainPanel.add(loadButton);
mainPanel.add(testButton);
mainPanel.add(loadImage);
mainPanel.add(textArea);
content.add(mainPanel);
}
}
You're adding the drawPad and the mainPanel to the content panel, which uses BorderLayout, without specifying any location. They thus end up both in the center position of the border layout, which is supposed to contain only one component.
See How to use BorderLayout in the Swing tutorial.
Also note that setting the preferred size is not something you should do. Instead, the preferred size is supposed to be automatically computed based on other sttings (the contained components, the number of rows and columns of a text area, etc.)
And a JTextArea should be enclosed into a JScrollPane to be good-looking and allow you to scroll.
JPanel mainPanel = new JPanel();
The default layout for a JPanel is a FlowLayout, so all the components flow on a single row. If there is not enough room on the row then the components wrap to the next row.
So when you add the JTextArea the flow is disturbed. The solution is to use a combination of layout managers to get your desired layout effect. Read the section from the Swing tutorial on Using Layout Managers for more information and examples.
JTextArea textArea = new JTextArea(text);
textArea.setPreferredSize(new Dimension(500, 50));
Also, you should NOT set the preferred size of the text area (or any Swing component for that matter). Instead you should do something like:
JTextArea textArea = new JTextArea(rows, columns);
and let the component determine its own preferred size. Also a text area is typically used with a JScrollPane and then you add the scroll pane to your panel:
JScrollPane scrollPane = new JScrollPane( textArea );
Edit:
Taking a second look at your code you have many more problems.
The point of using a layout manager is to have the layout manager set the size and location of the components. So your code should not have any logic related to the size/location of a component.
When you use the add(...) statement on a BorderLayout without a constraint, the component gets added to the CENTER. However only the last component added is managed by the BorderLayout. So only the "mainPanel" is given a size/location by the layout manager. That is why you need the setSize(...) statement on the drawPad to make the component visible. Although you now have the problem that two components are painted in the same space.
So to see the drawPad on the left you might want to use:
content.add(drawPad.BorderLayout.LINE_START);
However this still probably won't work because I'm guessing you are doing custom painting on the draw pad which means you will also need to override the getPreferredSize() method of the class so the layout manager can use the information to determine the size of the component. Read the section from the Swing tutorial on Custom Painting for more information and working examples.
Finally some other issues:.
The setVisible(...) statement should be invoked AFTER all the components have been added to the frame.
To follow Java standards, class names should start with an upper case character.
You should NOT be extending "Frame". There is no need to extend any class in your example.
Read the tutorial and download the demos for examples of better structured code.

Text not displayed when mouse is rolled over JLabel

With NetBeans (Java), I am having problems in JLabel. I have assigned an image as the icon of that JLabel.
Problem - 1st:
I want to display some text (e.g - logout) below that icon (image). How to do this?
Problem - 2nd:
I want to display some text when mouse is rolled over that JLabel. What should I do?
So , please guys tell me how to these things by writing code.
I recommend reading the basic Oracle tutorials which describe in detail how to accomplish this. You can use a MouseMotionListener to determine when the mouse is rolled over the JLabel, and you can position the JLabel text underneath the Icon of the JLabel by setting its vertical text position as described in the JLabel Tutorial. This should have all been found with a simple internet search of your questions, something that your question suggests was not done (and should have been) before asking
1.
Create a JPanel that contains two JLabels. This way you can control the layout of the internal components.
I used BoxLayout with the parameter BoxLayout.Y_AXIS to get the label below the icon.
2.
Add a MouseListener using the method component.addMouseListener(new MouseAdapter() { ... });, you'll need to create a MouseAdapter and implement any methods you need (click here).
Here is a working example for you buddy... Adapt this however you need to.
Note: You'll need to change the file-path of the ImageIcon()
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel container = new JPanel();
JPanel iconLabelPanel = new JPanel();
String TEXT_FIELD_TEXT = "Hover over the logout label.";
JLabel icon = new JLabel(new ImageIcon("C:\\Users\\Gary\\Google Drive\\Pictures\\puush\\ss (2015-02-19 at 06.00.00).png"));
JLabel label = new JLabel("Logout!");
JTextField textField = new JTextField(TEXT_FIELD_TEXT);
//Add a mouse motion listener for the JLabel
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
//Set text of another component
textField.setText("You're over Logout!");
}
#Override
public void mouseExited(MouseEvent e) {
//Set text of another component
textField.setText(TEXT_FIELD_TEXT);
}
});
//Add components and set parameters for iconLabelPanel
iconLabelPanel.setLayout(new BoxLayout(iconLabelPanel, BoxLayout.PAGE_AXIS));
iconLabelPanel.add(icon);
iconLabelPanel.add(label);
//Add components and set parameters for container
container.setLayout(new BoxLayout(container, BoxLayout.PAGE_AXIS));
container.add(iconLabelPanel);
container.add(textField);
//Set parameters for frame
frame.add(container);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setSize(400, 400);
frame.setVisible(true);
}

JButton not visible until mouseover

I'm creating a gui for my project. When the gui is first loaded only background is visible, so buttons are not visible, but when mouse over them, they are visible. What is the solve this problem?
public class Home extends JFrame{
//New JPanel
private JPanel home;
//Creating image url. You must be change url
ImageIcon icon = new ImageIcon("img//home1.jpeg");
//Home Class
public Home(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 960, 640);
setTitle("LoneyTunes Crush");
home = new JPanel();
home.setBorder(new EmptyBorder(5, 5, 5, 5));
home.setLayout(new BorderLayout(0, 0));
setContentPane(home);
getContentPane().setLayout(null);
JLabel background = new JLabel(new ImageIcon("img//giphy."));
getContentPane().add(background);
background.setLayout(new FlowLayout());
//Creating Buttons
JButton play = new JButton("Play");
play.setBounds(20, 20, 200, 30);
JButton setting = new JButton("Settings");
setting.setBounds(20, 60, 200, 30);
JButton exit = new JButton("Exit");
exit.setBounds(20, 100, 200, 30);
//Adding Buttons
home.add(play);
home.add(setting);
home.add(exit);
//ActionListeners
play.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
home.setVisible(false);
difficulty.setVisible(true);
}
});
exit.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
System.exit(1);
}
});
validate();
}
//Background paint method
public void paint(Graphics g){
g.drawImage(icon.getImage(), 0, 0, getWidth(), getHeight(), null);
}
}
Main Class
public class MainClass {
public static Home pencere;
public static void main(String args[]){
pencere=new Home();
pencere.setVisible(true);
}
}
Don't paint on top-level containers like JFrame as they already carry the burden of painting all of it's components.
Instead paint on JPanel or JComponent and Override it's paintComponent method.
On top of overriding paintComponent (or in your case paint), you need to also call super.paintComponent (in your case super.paint) inside the the method (first call under the method signature), as to not break the paint chain. Failing to do so may and probably will leave you with undesired paint artifacts.
Avoid using null layouts for a number of reason. Different platform will treat them differently. They are difficult to maintain, among many other reasons. Instead use layout managers, and let them do the laying out and sizing of the components, as they were designed to do with Swing apps. Learn more at Laying out components Within a Container
Setting Home pancere as a static class member of MainClass is completely pointless. Just declare and instantiate both in the main method.
Swing apps should be run on the Event Dispatch Thread (EDT). You can do so by wrapping your the code inside your main method with a SwingUtilities.invokeLater.... See more at Initial Threads
Instead of trying to make panels visible and not visible or adding an removing panel, consider using a CardLayout which will "layer" panels, and you can navigate through them with CardLayout's methods like show(), next(), previous(). See more at How to Use CardLayout
By time of deployments, the images you are using will need to become embedded resources, and should be loaded from the class path, and not from the file system. When you pass a String to ImageIcon, you are telling the program to look in the file system, which may work in your development environment, but that's it. See the wiki tag on embedded-resource an pay close attention to the very last link that will provide you will some resources on how to use and load embedded resources if the info doesn't provide enough detail.
Problem is with
getContentPane().setLayout(null);
remove it as you have already set the layout to a Border Layout and you will see all these buttons.
Just make sure that the setvisibility of all other panels except the one which you wish to display is set to false.I too had a similar problem but i had forgotten to set visibility of one of the 10 panels to false.Problem resolved once i set it to false.
I don't know how this worked for me I just typed jf.setVisible(true); at the end after adding all the GUI codes.
public Calculator(){
jf = new JFrame("Basic Calculator");
jf.setLayout(GridBagLayout);
jf.setSize(306, 550);
jf.setLocation(530, 109);
//all the GUI things like JButton, JLabel, etc...
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Try putting validate(); method on your main frame. I think it would help you.

How do I remove the blue border highlight that appears when selecting a tab in a JTabbedPane?

This is sort of a continuation of my previous question, but it addresses a specific concern that could be useful to someone else so I thought I would post it as a individual question.
I have successfully created a JTabbedPane but there is an blue border highlight that shows which tab has been selected that I would like to remove:
To clarify what I mean here is a picture of a JTabbedPane without the blue border highlight from Eclipse:
The things I have tried have been commented out:
public class SeaGlassExercise {
public static void initWindow() {
JFrame frame = new JFrame("Application Name");
CustomTabbedPane content = new CustomTabbedPane();
frame.setContentPane(content);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(true);
// try {
// UIManager.setLookAndFeel(
// UIManager.getSystemLookAndFeelClassName());
// } catch (Exception e) {
// e.printStackTrace();
// }
// SwingUtilities.updateComponentTreeUI(frame);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initWindow();
}
});
}
}
class CustomTabbedPane extends JPanel {
public CustomTabbedPane() {
super(new GridLayout(1, 1));
// UIManager.put("TabbedPane.contentAreaColor", Color.GREEN);
// UIManager.put("TabbedPane.light", ColorUIResource.GREEN);
// UIManager.put("TabbedPane.highlight", ColorUIResource.GREEN);
// UIManager.put("TabbedPane.shadow", ColorUIResource.GREEN);
// UIManager.put("TabbedPane.darkShadow", ColorUIResource.GREEN);
// UIManager.put("TabbedPane.selected", ColorUIResource.GREEN);
// UIManager.put("TabbedPane.borderHightlightColor", ColorUIResource.GREEN);
// UIManager.put("TabbedPane.borderHightlightColor", ColorUIResource.GREEN);
// UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0));
JTabbedPane tabbedPane = new JTabbedPane();
JComponent panel1 = makeTextPanel("Panel #1");
tabbedPane.addTab("AAA", panel1);
JComponent panel2 = makeTextPanel("Panel #2");
tabbedPane.addTab("BBB", panel2);
JComponent panel3 = makeTextPanel("Panel #3");
tabbedPane.addTab("CCC", panel3);
JComponent panel4 = makeTextPanel("Panel #4");
tabbedPane.addTab("DDD", panel4);
add(tabbedPane);
tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
}
protected JComponent makeTextPanel(String text) {
JPanel panel = new JPanel();
JLabel filler = new JLabel(text);
filler.setHorizontalAlignment(JLabel.CENTER);
panel.setLayout(new GridLayout(1, 1));
panel.add(filler);
return panel;
}
}
Additional Information
I am currently running my program with OS X Mountain Lion along with java version "1.7.0_25", Java(TM) SE Runtime Environment (build 1.7.0_25-b15). I am using the default look and feel (i.e. I have not specified anything with .setUI() in my code).
Here are some questions I have looked at:
Controlling Color in Java Tabbed Pane
JTabbedPane - set default border around tabs..?
remove blue color from JTabbedPane
Note the current approach may not work with other platforms / look and feels. If your current project is intended to work only on your Mac and you don't plan change this in the future, well in that case it might work. But normally Java applications are intended to work across different platforms and look and feels.
Having said this you may want to take a look to this interesting article about most popular look and feels defaults: All UI defaults names for common Java look and feels on Windows, Mac OS X, and Linux. When you look at the tables then you'll see not all L&Fs support the same properties and may ignore them when create an UI object (f.i. TabbedPaneUI).
If you like Mac L&F (I do) then I'd suggest you try customizing Seaglass Look and Feel which is pretty similar than Mac's. This way you will get this benefits:
Standard cross-platform L&F similar to Mac's L&F provided with your app.
Customize the L&F and this change will be also cross-platform.
Unify user experience (non trivial matter). Probably you and me will be able to work with the same app on Mac OS, Windows or Linux with different L&F. But many users can't do it: they get lost when the GUI looks different.
To customize Seaglass you can list the default properties as follow:
for(Object key : UIManager.getLookAndFeel().getDefaults().keySet()) {
System.out.println(key + " = " + UIManager.get(key));
}
These are quite much and I really don't have time enough to give you a working example so I hope the idea is good enough to help you.
Note
If you don't want frames and dialogs have the default decoration provided with Seaglass (it's pretty ugly to me) then you need to do as follw:
UIManager.setLookAndFeel(new SeaGlassLookAndFeel());
JFrame.setDefaultLookAndFeelDecorated(false);
JDialog.setDefaultLookAndFeelDecorated(false);
This way frames and dialogs will have their Window decorations provided by the current window manager (up to the OS).
I know the correct visual solution to remove tabs' border:
tabbedPane.setFocusable(false);
But you lost posibility to use keys for tabbed pane.
I believe setting the border will remove these... it does on a JTextField.
For example:
JTextField field = new JTextField();
field.setBorder(new EmptyBorder(3, 3, 3, 3));
This removes the blue focus border.

Custom Java tool tip with Swing components as content does not show up

I'm trying to show multiple images in a component's tooltip, found createToolTip() and implemented a custom that adds the needed components like this:
setComponent(component);
JPanel images = new JPanel(null);
images.setLayout(new BoxLayout(images, BoxLayout.X_AXIS));
for(ImageIcon icon:myIcons) {
images.add(new JLabel(icon));
}
JPanel content = new JPanel(new BorderLayout());
content.add(new JLabel(title), BorderLayout.NORTH);
content.add(new JLabel(description));
content.add(images, BorderLayout.SOUTH);
add(content);
However, all I see is a little dot, indicating that the tool tip is shown, but somehow the size is ignored. What do I miss implementing a custom tooltip?
Tool tips can render HTML. If you can form URLs to the images (not practical if they are generated in memory but usually doable otherwise), it is an easy matter to write some HTML that will load the images, and use that HTML as the tool tip.
E.G.
import javax.swing.*;
class MultiIconToolTip {
public static void main(String[] args) throws Exception {
final String html =
"<html><body>" +
"<img src='" +
"http://i.stack.imgur.com/OVOg3.jpg" +
"' width=160 height=120> " +
"<img src='" +
"http://i.stack.imgur.com/lxthA.jpg" +
"' width=160 height=120>" +
"<p>Look Ma, no hands!";
SwingUtilities.invokeLater( new Runnable() {
public void run() {
JLabel hover = new JLabel("Point at me!");
hover.setToolTipText(html);
JOptionPane.showMessageDialog(null, hover);
}
});
}
}
The base "problems" are that JToolTip
is-not designed as a container, it's only accidentally a container because JComponent is. For a Swing "not-container" its the responsibility of the ui-delegate to act as LayoutManager.
isn't rich enough, it can handle text-only (at least with the emergency door html, which is #Andrew's favourite :-)
By-passing those limitations basically is a driving that widget nearly over the edge. A clean solution would roll a new component .. On the other hand, the OP already found the screws to tweak. The only thingy that could be slightly improved is to neither call setXXSize, nor set a custom ui. Instead, make it behave like a container by overriding getXXSize() like:
#Override
public Dimension getPreferredSize() {
if (getLayout() != null) {
return getLayout().preferredLayoutSize(this);
}
return super.getPreferredSize();
}
I'd suggest to using JWindow or un_decorated JDialog, as popup window (used by default for JCalendar or JDatePicker) rather than JTooltip, for nicer output to the GUI implements Translucent and Shaped Windows
NOTE:
If you use JDK 1.6 or older, use this method instead.
It only works with SUN JDK.
There are essentially two things missing. First of all, JToolTip extends JComponent, and unlike JPanel, it doesn't have a default layout. To stretch the content across the tooltip, use a BorderLayout.
setLayout(new BorderLayout());
The second problem is the size. The ToolTipManager respects the preferred size of the tool tip. While the BorderLayout calculates the size, the ToolTipUI ignores it. So, there are two alternatives: Manually set the preferred size...
setPreferredSize(content.getPreferredSize());
Note that this does not make the layout obsolete; otherwise, you get an empty tool tip with the right size.
... or subclass ToolTipUI to respect the layout, which is what I went with. The resulting code is:
setComponent(StadtLabel.this);
JPanel images = new JPanel(null);
waren.setLayout(new BoxLayout(waren, BoxLayout.X_AXIS));
for(ImageIcon icon:myIcons) {
JLabel lbl = new JLabel(icon);
}
JPanel content = new JPanel(new BorderLayout());
content.add(new JLabel(title), BorderLayout.NORTH);
content.add(new JLabel(description));
content.add(images, BorderLayout.SOUTH);
setLayout(new BorderLayout());
add(content);
setUI(new ToolTipUI() {
#Override
public Dimension getMinimumSize(JComponent c) {
return c.getLayout().minimumLayoutSize(c);
}
#Override
public Dimension getPreferredSize(JComponent c) {
return c.getLayout().preferredLayoutSize(c);
}
#Override
public Dimension getMaximumSize(JComponent c) {
return getPreferredSize(c);
}
});
Instead of reinventing the wheel try this: https://github.com/timmolderez/balloontip. You can put any content as JComponent.

Categories