I have the following lines to get a tooltip text for a JList item :
JList aList=new JList(aData)
{
public String getToolTipText(MouseEvent evt) // This method is called as the cursor moves within the list.
{
String tooltipText="Some tooltip";
int tooltipWidth= ?
return tooltipText;
}
}
Inside getToolTipText(), how do I get the tooltipText width?
You can use FontMetrics to determine the size of some text.
FontMetrics metrics = graphics.getFontMetrics(font);
int adv = metrics.stringWidth(text);
http://docs.oracle.com/javase/tutorial/2d/text/measuringtext.html
To find the used font you can query the LookAndFeel you are using
UIDefaults uidefs = UIManager.getLookAndFeelDefaults();
Font font = uidefs.getFont("ToolTip.font");
System.out.println(font);
// prints: FontUIResource[family=Dialog,name=Dialog,style=plain,size=12]
To know the keys you can use ("ToolTip.font" here), you can check the documentation of the default LookAndFeels in Swing, for example Nimbus:
http://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/_nimbusDefaults.html#primary
I form my tooltip in html like this : "<html>first line<Br>========<Br>second line</html>", I want the separator line "=====" to match the length of the first line, so it can look nicer, ..
Consider alternatives 2 & 3, both of which require no calculation and look better than the 'row of equals signs'.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.LineBorder;
public class HtmlToolTip {
HtmlToolTip() {
String attempt1 = "<html>first line 1<Br>========<Br>second line</html>";
JLabel label1 = new JLabel(attempt1);
label1.setBorder(new LineBorder(Color.BLACK));
String attempt2 = "<html><u>first line 2</u><br>second line</html>";
JLabel label2 = new JLabel(attempt2);
label2.setBorder(new LineBorder(Color.BLACK));
String attempt3 = "<html>first line 3<hr>second line</html>";
JLabel label3 = new JLabel(attempt3);
label3.setBorder(new LineBorder(Color.BLACK));
JPanel p = new JPanel(new FlowLayout(FlowLayout.LEADING,5,5));
p.add(label1);
p.add(label2);
p.add(label3);
JOptionPane.showMessageDialog(null, p);
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new HtmlToolTip();
}
});
}
}
Thanks to the answer, I figured it out, here is what I did :
UIDefaults uidefs=UIManager.getLookAndFeelDefaults();
Font font=uidefs.getFont("ToolTip.font");
GraphicsEnvironment ge=GraphicsEnvironment.getLocalGraphicsEnvironment();
Graphics2D g2d=ge.createGraphics(new BufferedImage(1,1,1));
FontMetrics fontMetrics=g2d.getFontMetrics();
Top_Line_Width=fontMetrics.stringWidth("Toptip text");
Related
I have a JTable for which the renderer returns a JPanel composed of multiple JLabel instances. One of those JLabels can contain HTML used among other things to split the output over multiple lines using <br/> tags.
To show the multiple lines in the table, the renderer calls in the getTableCellRendererComponent method
table.setRowHeight(row, componentToReturn.getPreferredSize().height);
to dynamically update the row height, based on the contents. This only works correctly if componentToReturn indicates a correct preferred size.
It looks however that the getPreferredSize returns bogus values. The preferred height of the returned component is smaller than the sum of the heights of the labels inside the component.
Here is a little program illustrating this behaviour (without using a JTable)
import java.awt.*;
import javax.swing.*;
public class SwingLabelTest {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
LabelPanel renderer = new LabelPanel();
Component component = renderer.getComponent(false);
//asking for a bigger component will not
//update the preferred size of the returned component
component = renderer.getComponent(true);
}
});
}
private static class LabelPanel {
private final JPanel compositePanel;
private final JLabel titleLabel = new JLabel();
private final JLabel propertyLabel = new JLabel();
public LabelPanel() {
JPanel labelPanel = new JPanel();
labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.PAGE_AXIS));
labelPanel.add(titleLabel);
labelPanel.add(propertyLabel);
compositePanel = new JPanel(new BorderLayout());
//normally it contains more components,
//but that is not needed to illustrate the problem
compositePanel.add(labelPanel, BorderLayout.CENTER);
}
public Component getComponent( boolean aMultiLineProperty ) {
titleLabel.setText("Title");
if ( aMultiLineProperty ){
propertyLabel.setText("<html>First line<br/>Property: value</html>");
} else {
propertyLabel.setText("Property: value");
}
int titleLabelHeight = titleLabel.getPreferredSize().height;
int propertyLabelHeight = propertyLabel.getPreferredSize().height;
int compositePanelHeight = compositePanel.getPreferredSize().height;
if ( compositePanelHeight < titleLabelHeight + propertyLabelHeight){
throw new RuntimeException("Preferred size of the component returned "
+ "by the renderer is incorrect");
}
return compositePanel;
}
}
}
As I am aware that the previous example is a bit far-fetched, here an example which includes a JTable
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class SwingTableTest {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
DefaultTableModel tableModel = new DefaultTableModel(0, 1);
JTable table = new JTable(tableModel);
table.setDefaultRenderer(Object.class, new DataResultRenderer());
tableModel.addRow(new Object[]{new Object()});
tableModel.addRow(new Object[]{new Object()});
tableModel.addRow(new Object[]{new Object()});
JFrame testFrame = new JFrame("TestFrame");
testFrame.getContentPane().add(new JScrollPane(table));
testFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
testFrame.setSize(new Dimension(300, testFrame.getPreferredSize().height));
testFrame.setVisible(true);
}
});
}
private static class DataResultRenderer implements TableCellRenderer {
private final JPanel compositePanel;
private final JLabel titleLabel = new JLabel();
private final JLabel propertyLabel = new JLabel();
public DataResultRenderer() {
JPanel labelPanel = new JPanel();
labelPanel.setOpaque(false);
labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.PAGE_AXIS));
labelPanel.add(titleLabel);
labelPanel.add(propertyLabel);
compositePanel = new JPanel(new BorderLayout());
//normally it contains more components,
//but that is not needed to illustrate the problem
compositePanel.add(labelPanel, BorderLayout.CENTER);
}
#Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
titleLabel.setText("Title");
if ( row == 2 ){
propertyLabel.setText("<html>Single property: value</html>");
} else {
String text = "<html>";
text += "First property<br/>";
text += "Second property<br/>";
text += "Third property:value";
text += "</html>";
propertyLabel.setText(text);
}
int titleLabelHeight = titleLabel.getPreferredSize().height;
int propertyLabelHeight = propertyLabel.getPreferredSize().height;
int compositePanelHeight = compositePanel.getPreferredSize().height;
if ( compositePanelHeight < titleLabelHeight + propertyLabelHeight){
throw new RuntimeException("Preferred size of the component returned "
+ "by the renderer is incorrect");
}
table.setRowHeight(row, compositePanel.getPreferredSize().height);
return compositePanel;
}
}
}
I am looking for a way to update the row height of the table to ensure that the multi-line content is completely visible, without knowing up front how many lines each row will contain.
So either I need a solution to retrieve the correct preferred size, or my approach is completely wrong and then I need a better one.
Note that the above examples are simplified. In the real code, the "renderer" (the code responsible for creating the component) is decorated a few times. This means that the outer renderer is the only with access to the JTable, and it has no knowledge about what kind of Component the inner code returns.
Because setRowHeight() "Sets the height, in pixels, of all cells to rowHeight, revalidates, and repaints," the approach is unsound. Absent throwing an exception, profiling shows 100% CPU usage as an endless cascade of repaints tries to change the row height repeatedly. Moreover, row selection becomes unreliable.
Some alternatives include these:
Use TablePopupEditor to display multi-line content on request from a TableCellEditor.
Update an adjacent multi-line panel from a TableModelListener, as shown here.
I tried this: Code Zip
Sorry for the inconvenience but I could not attach the whole code (though it's not too big) and could not provide .java extension link so you have to get the zip and it open in html where code is with syntax highlighting.
I read these:
Java GUI - JOptionPane/JDialog customization issue
How to make font bold in java dialogue box?
But I don't want to use HTML.
Code
public static void main(String argv[]) {
JFrame jf;
jf = new JFrame();
JPanel jp = new JPanel();
jf.setBounds(100, 100, 530, 350);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.getContentPane().setLayout(null);
jp.setFont(new Font("Algerian", Font.ITALIC, 11));
jf.add(jp);
String message = "Hello World!”;
JOptionPane jop;
jop = new JOptionPane();
Object[] obj = { UIManager.put("Panel.font",new Font("Algerian", Font.ITALIC, 11)) , message };
JOptionPane.showMessageDialog(jp,obj,"Dialog",JOptionPane.NO_OPTION);
}
This MCVE shows one label in 3 option panes with 3 different variants of the same (default) font. It is simply a matter of passing the option pane a component that has the font set, as opposed to a string or a generic object.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class FontInOptionPane {
FontInOptionPane() {
JLabel l = new JLabel();
Font f = l.getFont();
l.setText(f.toString());
JOptionPane.showMessageDialog(null, l);
f = f.deriveFont(Font.ITALIC);
l.setText(f.toString());
l.setFont(f);
JOptionPane.showMessageDialog(null, l);
f = f.deriveFont(50f);
l.setText(f.toString());
l.setFont(f);
JOptionPane.showMessageDialog(null, l);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
new FontInOptionPane();
}
};
SwingUtilities.invokeLater(r);
}
}
In Java Swing, you globally set your JOptionPane font by using the following code lines:
UIManager.put("OptionPane.messageFont", new Font("Arial", Font.PLAIN, 15));
UIManager.put("OptionPane.buttonFont", new Font("Arial", Font.PLAIN, 18));
This works like a charm.
I have created a combo-box in java (using Netbeans). I want to set the text size of each item in the list but don't know how to do it. (Preferably I want to use the default font style).
Any idea anyone how to do it?
Code Snippet:
private javax.swing.JComboBox ComboBox_agent = new javax.swing.JComboBox();
ComboBox_agent.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "TCP", "UDP", "Sink", "NULL" }));
Use a list cell rendering component with an appropriate font size. This example uses 20 pixels.
import java.awt.*;
import javax.swing.*;
class ShowFonts {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
GraphicsEnvironment ge = GraphicsEnvironment.
getLocalGraphicsEnvironment();
String[] fonts = ge.getAvailableFontFamilyNames();
JComboBox fontChooser = new JComboBox(fonts);
fontChooser.setRenderer(new FontCellRenderer());
JOptionPane.showMessageDialog(null, fontChooser);
});
}
}
class FontCellRenderer extends DefaultListCellRenderer {
#Override
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
JLabel label = (JLabel)super.getListCellRendererComponent(
list,value,index,isSelected,cellHasFocus);
Font font = new Font((String)value, Font.PLAIN, 20);
label.setFont(font);
return label;
}
}
If you created the JComboBox in Netbeans GUI editor, there is a field for "Font" that allows you to change the size.
This question already has answers here:
Create a autocompleting textbox in Java with a dropdown list
(7 answers)
Closed 10 years ago.
Algorithm
Start
Input a city name - partial or complete
If the user hits enter , take the text from JTextField
Begin brute force search.
If the matches are found, put them in a Vector and put it in a JList
If no match is found, add a String "No Match Found" in Vector
Display JWindow to user containing the results
Stop
Code:
package test;
import javax.swing.*;
import java.awt.Dimension;
import java.awt.event.*;
import java.util.Vector;
public class AutoCompleteTest extends JFrame{
JTextField city = new JTextField(10);
String enteredName = null;
String[] cities = {"new jersey","new hampshire",
"sussex","essex","london","delhi","new york"};
JList list = new JList();
JScrollPane pane = new JScrollPane();
ResultWindow r = new ResultWindow();
//------------------------------------------------------------------------------
public static void main(String[] args) {
new AutoCompleteTest();
}
//------------------------------------------------------------------------------
public AutoCompleteTest(){
setLayout(new java.awt.FlowLayout());
setVisible(true);
add(city);
// add(pane);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
city.addKeyListener(new TextHandler());
}
//------------------------------------------------------------------------------
public void initiateSearch(String lookFor){
Vector<String> matches = new Vector<>();
lookFor = lookFor.toLowerCase();
for(String each : cities){
if(each.contains(lookFor)){
matches.add(each);
System.out.println("Match: " + each);
}
}
this.repaint();
if(matches.size()!=0){
list.setListData(matches);
r.searchResult = list;
r.pane = pane;
r.initiateDisplay();
}else{
matches.add("No Match Found");
list.setListData(matches);
r.searchResult = list;
r.pane = pane;
r.initiateDisplay();
}
}
//------------------------------------------------------------------------------
public class ResultWindow extends JWindow{
public JScrollPane pane;
public JList searchResult;
//------------------------------------------------------------------------------
public ResultWindow(){
}
//------------------------------------------------------------------------------
public void initiateDisplay(){
pane.setViewportView(searchResult);
add(pane);
pack();
this.setLocation(AutoCompleteTest.this.getX() + 2,
AutoCompleteTest.this.getY()+
AutoCompleteTest.this.getHeight());
// this.setPreferredSize(city.getPreferredSize());
this.setVisible(true);
}
}
//------------------------------------------------------------------------------
class TextHandler implements KeyListener{
#Override
public void keyTyped(KeyEvent e){
}
#Override
public void keyPressed(KeyEvent e){
if(r.isVisible()){
r.setVisible(false);
}
if(e.getKeyChar() == '\n'){
initiateSearch(city.getText());
}
}
#Override
public void keyReleased(KeyEvent e){
}
}
//------------------------------------------------------------------------------
}
Output
Problem
The size of the JWindow displaying the results (which is a JList in a JScrollPane) changes based on the results - if the city name is small, JWindow is small, if the city name is big, JWindow is big.
I have tried every possible combination. I tried using setPreferredDimension() of the JWindow, the JList and JScrollPane but the issue won't go.
I want it to match the size of the decorated JFrame no matter what
JList or JComboBox doesn't returns proper PreferredSize, have to set this value, use JList.setPrototypeCellValue() with pack() for JWindow (must be packed after any changes) and or with JList.setVisibleRowCount(), then value returns getPreferredScrollableViewportSize() for JList in JScrollPane
don't to use KeyListener, use DocumentListener (chars can be inserted from system clipboard) for JTextComponents
don't to reinvent the wheel, use AutoComplete JComboBox / JTextField, you can to redirect / returns result from matches to the popup JWindow / undecorated JDialog(quite the best workaround for popup recycle)
EDIT
Anyways so basically I will have to manually create a list of all the
cities that are to be supported right ?? bx #Little Child
this idea could be quite easy, you can to put JTable to the JWindow
with one Column,
without JTableHeader
add there RowSorter (see code example in tutorial)
then every steps are done :-), nothing else is required there (maybe bonus to change Background of JTextField in the case that RowFilter returns no matches, add setVisible for popup window from DocumentListener (be sure to test for !isVisible))
You should use JComboBox, and for the autocompletion, read this article.
You need to use the width of the the JFrame every time you initiate the search and use it calculate the width of the list.
Just change the initiateSearch() function like this:
public void initiateSearch(String lookFor){
//add the following two statements to set the width of the list.
int newWidth = AutoCompleteTest.this.getSize().width;
list.setPreferredSize(new Dimension(newWidth, list.getPreferredSize().height));
Vector<String> matches = new Vector<String>();
lookFor = lookFor.toLowerCase();
for(String each : cities){
if(each.contains(lookFor)){
matches.add(each);
System.out.println("Match: " + each);
}
}
this.repaint();
if(matches.size()!=0){
list.setListData(matches);
r.searchResult = list;
r.pane = pane;
r.initiateDisplay();
}else{
matches.add("No Match Found");
list.setListData(matches);
r.searchResult = list;
r.pane = pane;
r.initiateDisplay();
}
}
Here is a sample output:
and
PS: Just for better aesthetics try using some layout to make the text field fill the entire width.
One solution would be to change initiateDisplay() to this:
public void initiateDisplay()
{
this.pane.setViewportView(this.searchResult);
this.add(this.pane);
this.pack();
this.setLocation(AutoCompleteTest.this.getX() + 2, AutoCompleteTest.this.getY()
+ AutoCompleteTest.this.getHeight());
int padding = 5;
int height = this.searchResult.getModel().getSize()
* AutoCompleteTest.this.city.getSize().height;
int windowWidth = AutoCompleteTest.this.getSize().width;
this.setSize(windowWidth, height);
this.setVisible(true);
}
I've searched and researched in everywhere I could to find an answer with no result. So I ask for help once more.
I want to show formatted text in a desktop java swing application. This text would be programactly generated in base of some variable objects and wouldn't be editable.
I don't know if is best to use JTextPane, or JEditorPane, or what. The matter is that I don't find anywhere some manual or tutorial that explain how to use them. Do I have to create an HTMLDocument to insert the text? How do I create it?...
Is is the right way to show text in this case?, or may I go using tables or labels or something like that.
I need some advice from you please, if there is some where I could learn how to do it, tell me please.
Here have a look at this code example, if you want to modify this a bit more, add Font too as an argument and use that appropriate argument at the specified location. Write something in the JTextField and press ENTER several times.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.text.AttributeSet;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
public class TextPaneTest extends JFrame {
private JPanel topPanel;
private JTextPane tPane;
private JTextField tfield;
private int counter;
private Color[] colours = {
Color.RED,
Color.BLUE,
Color.DARK_GRAY,
Color.PINK,
Color.BLACK,
Color.MAGENTA,
Color.YELLOW,
Color.ORANGE
};
public TextPaneTest() {
counter = 0;
}
private void createAndDisplayGUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
EmptyBorder eb = new EmptyBorder(new Insets(10, 10, 10, 10));
tPane = new JTextPane();
tPane.setBorder(eb);
tPane.setMargin(new Insets(5, 5, 5, 5));
JScrollPane scroller = new JScrollPane();
scroller.setViewportView(tPane);
tfield = new JTextField();
tfield.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
counter++;
if (counter == 8)
counter = 0;
String text = tfield.getText() + "\n";
appendToPane(tPane, text, colours[counter]);
tfield.selectAll();
}
});
getContentPane().add(scroller, BorderLayout.CENTER);
getContentPane().add(tfield, BorderLayout.PAGE_END);
setSize(200, 100);
setVisible(true);
tfield.requestFocusInWindow();
}
private void appendToPane(JTextPane tp, String msg, Color c) {
StyleContext sc = StyleContext.getDefaultStyleContext();
AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, c);
aset = sc.addAttribute(aset, StyleConstants.FontFamily, "Lucida Console");
aset = sc.addAttribute(aset, StyleConstants.Alignment, StyleConstants.ALIGN_JUSTIFIED);
int len = tp.getDocument().getLength();
tp.setCaretPosition(len);
tp.setCharacterAttributes(aset, false);
tp.replaceSelection(msg);
}
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TextPaneTest().createAndDisplayGUI();
}
});
}
}
I've searched and researched in everywhere I could to find an answer with no result. So I ask for help once more.
everything is described with required details in the Oracle How to Use Editor Panes and Text Panes, including support for styled text
Do I have to create an HTMLDocument to insert the text? How do I create it?...
not you don't need to create a HTML contens, about HTML is Oracle tutorial How to Use HTML in Swing Components
Is is the right way to show text in this case?, or may I go using tables or labels or something like that.
for styled text is JEditorPane / JTextPane best of the choices
examples in the tutorial or here