In my application i have 2 types of editfields. One of them behaves like single line editfield, the other behaves like multi-line editfield (editarea). In this screen i have one header, one editfield and one editarea. When i enter some text to editfield, it clips the text and cursor. But, when i enter some text to editarea which includes a tailed character(y,g,q,p) editareas height is changing and editfieldact normal. If i dont enter tailed characters stuation does not change.
Here is my editarea class:
public class EditAreaField extends HorizontalFieldManager{
private net.rim.device.api.ui.component.EditField editArea;
public EditAreaField (){
// some code;
editArea.setPadding(25, 10, 0, 10);
}
public int getPreferredHeight() {
int height = Math.max(editArea.getHeight(), textFont.getHeight());
return height + editArea.getPaddingTop();
}
}
label1 -> editfield
label2 -> editarea
this is because you are making the size to change by using
int height = Math.max(editArea.getHeight(), textFont.getHeight());
instead of this try to give some fixed height. for example
height= Graphics.getScreenHeight()/5;
or you can also use setExtent inside the sublayout method of the manager
protected void sublayout(int maxWidth, int maxHeight)
{
layoutChild(_editField, _editField.getPreferredWidth(), _editField.getPreferredHeight());
setPositionChild(_editField, xpos,ypos);
setExtent(preferredHeight,preferredWidth);
}
I think it will work.
Please let me know
About the cursor painting - you did override drawFocus or/and onFocus or/and onUnfocus and don't repaint properly sometime.
Related
Basically, I'm trying to make a button that has the text aligned to the left (so I'm using setHorizontalAlignment(SwingConstants.LEFT)) and the image on the right border of the button, far from the text.
I already tried setHorizontalTextAlignment(SwingConstants.LEFT), but that just makes the text go relativity to the left of the icon, which is not exactly what I want, since I needed the icon to be secluded from it.
Also, I can't make any fixed spacing because it's a series of buttons with different texts with different sizes.
I can't make any fixed spacing because it's a series of buttons with different texts with different sizes.
You can dynamically change the spacing with code like:
JButton button = new JButton("Text on left:")
{
#Override
public void doLayout()
{
super.doLayout();
int preferredWidth = getPreferredSize().width;
int actualWidth = getSize().width;
if (actualWidth != preferredWidth)
{
int gap = getIconTextGap() + actualWidth - preferredWidth;
gap = Math.max(gap, UIManager.getInt("Button.iconTextGap"));
setIconTextGap(gap);
}
}
};
button.setIcon( new ImageIcon("copy16.gif") );
button.setHorizontalTextPosition(SwingConstants.LEADING);
This is a derivative of camickr's answer to allow editing in a GUI builder as well as placing it in a dynamic layout. I also removed the UIManager.getInt("Button.iconTextGap") so the gap will shrink to 0 if necessary.
I called it a 'Justified' button in analogy with justified text alignment (stretches a paragraph to left & right by growing width of space characters).
public class JustifiedButton extends JButton {
#Override
public void doLayout() {
super.doLayout();
setIconTextGap(0);
if (getHorizontalTextPosition() != CENTER) {
int newGap = getSize().width - getMinimumSize().width;
if (newGap > 0)
setIconTextGap(newGap);
}
}
#Override
public Dimension getMinimumSize() {
Dimension minimumSize = super.getMinimumSize();
if (getHorizontalTextPosition() != CENTER)
minimumSize.width -= getIconTextGap();
return minimumSize;
}
#Override
public Dimension getPreferredSize() {
Dimension preferredSize = super.getPreferredSize();
if (getHorizontalTextPosition() != CENTER)
preferredSize.width -= getIconTextGap();
return preferredSize;
}
}
This is not exactly production-ready and needs some field-testing. If I find anything, I'll edit the code.
[edit] Now works for vertical text alignments. Also simplified a bit.
[edit2] Also manipulate getPreferredSize to play nice with scroll pane (otherwise it keeps growing and never shrinks again)
You can add a layout manager to your button.
JButton btn = new JButton();
btn.add(new JLabel(text));
btn.add(new JLabel(img));
btn.setLayout(/*best layout choice here*/);
btn.setPreferredSize(new Dimension(x,y));
btn.setMaximumSize(new Dimension(maxX, minY));
btn.setMinimumSize(new Dimension(minX, minY)); //this one is most important when it comes to layoutmanagers
Sorry I can't be much help when it comes to picking out a good layout - But this will eventually get you what you want. Maybe someone else can comment on which one to use.
I have JLabel which I would like to change its size while I resize the window. When JLabel contains String which is too big, the String should be shortened, with right part visible and adds dots on the left hand side of the String.
My JLabel is inside innerPanel which is a header in middlePanel which is added to outerPanel. So when I resize window I use listener on outerPanel in that way:
outerPanel.addComponentListener(new ComponentListener() {
#Override
public void componentResized(ComponentEvent evt) {
int width = ((JPanel) evt.getSource()).getWidth();
windowSize = width;
refresh();
}
// [...] other not used override methods
});
refresh() repaints view and creates new middlePanel where is called class which creates innerPanel where is located my JLabel:
Public class InnerPanel extends JPanel {
private int maxSize;
String string = "<VERY_LONG_STRING>";
private static final int DEFAULT_INDEND_PIXEL = 70;
public InnerPanel(int windowSize) {
maxSize = windowSize - DEFAULT_INDENT_PIXEL;
createPanel();
}
private createPanel() {
// [...] gridbag and GridBagConstraints implementation
String shortString = countString();
JLabel label = new JLabel(shortString);
add(label,gc);
}
private String countString() {
int index = 0;
boolean toBig = true;
StringBuilder sb = new StringBuilder(string);
while(toBig) {
Rectangle2d rect = // [...] code which creates rectangle around text from sb.toString()
// I have no access to repo at home but if it's important I can paste it tomorrow
if(rect.getWidth() > maxSize)
sb.deleteCharAt(0);
else
toBig = false;
}
return sb.toString();
}
}
That's works fine in general, bacause it do resize JLabel in one step when I enlarge window in width. But the problem is appear when I try to reduce the window in width. In this case componentResized() calculate width step by step (and it's called multiple times), gradually decreases width by some amount of pixels till it reach real window size. It's behave in that way even thow I change window size in one step from maximum size to 800. Whole process is so slow, that it takes around a second to fit string to window size. So it looks bit like an animation.
The problem is very rare to me, bacause width in componentResized() method is calculeted step by step only when I assign windowSize variable.
When I give windowSize fixed size like for example 500 - componentResized() is called only onces - with correct width indicated real window size (!!) - and there's no its step by step decrease!
It's look like width variable which is assigned by ((JPanel) evt.getSource()).getWidth() knows that windowSize is used to dynamically change size of JLabel component even before first call of refresh() method.
If anyone have an idea what is going on here - I will be very appreciate for help.
You may be able to adapt one of the approaches shown here to better effect. As shown here, the ellipsis is supplied by the label's UI delegate via a call to SwingUtilities2.clipString(), which appends the clipString. Rather than re-invent the label UI, use TextLayout to determine the required geometry, prepend the ellipsis, and handle the alignment in a table or list renderer, as shown here.
I'm trying to find a way to change the line spacing in a JTextArea component.
A little bit of searching always seems to reveal the same answer: "Use a JTextPane instead and then call setParagraphAttributes".
But I'm wondering whether it's possible to achieve this with just a JTextArea by, for example, messing with the font.
With the deriveFont(...) method, it's possible to change the tracking and the kerning of the font, i.e. the horizontal spacing between characters, but I haven't been able to find a way to change the vertical spacing (maybe ascent, descent, leading). Am I missing something there?
As camickr pointed out, JTextArea does not provide a way to change the line height directly. It simply uses the font height provided by the corresponding FontMetrics.
But, this leaves a point of attack open using the following helper-class:
public class FontMetricsWrapper extends FontMetrics {
private final FontMetrics target;
public FontMetricsWrapper(FontMetrics target) {
super(target.getFont());
this.target = target;
}
#Override
public int bytesWidth(byte[] data, int off, int len) {
return target.bytesWidth(data, off, len);
}
#Override
public int charWidth(char ch) {
return target.charWidth(ch);
}
#Override
public int charWidth(int codePoint) {
return target.charWidth(codePoint);
}
// ... tons more #Override's, all of the same form:
//
// #Override
// public baz foo(bar, ...) {
// return target.foo(bar, ...);
// }
}
Then, it becomes possible to create the JTextArea like this:
JTextArea myTextArea = new JTextArea("Some text") {
#Override
public FontMetrics getFontMetrics(Font font) {
return new FontMetricsWrapper(super.getFontMetrics(font)) {
#Override
public int getHeight() {
return 10; // Gives line height in pixels
}
};
}
};
This is definitely not the cleanest solution and is merely meant as proof of concept. For example, one issue is that getFontMetrics(...) is called quite often, and, in the given example, creates a new instance of the wrapper class each time. So, at the very least, a HashMap that caches the created FontMetricsWrapper for each given font would be in order...
But, what I was really hoping for was a way to play with the Font or maybe the associated FontRenderContext passed into the JTextArea to modify the line height. For example, is there some way to influence font's reported ascent, descent, and leading values? Seems strange that you can change pretty much any other aspect of the font's appearance, except this one...
What's wrong with light-weight coding?
Nothing, you should use the simplest component for the job. But if the simple component doesn't support a requirement it is usually because the requirement is more complex and you need a more complex component to implement the functionality. Rarely would it be as simple at setting a property of a class.
Sometimes I'm simply interested in learning something new and figuring out what's possible.
Swing text components use a View to paint the text. It is the view's responsibility to format and position the text. So each view determines when to wrap and where to position the next line.
In the case of a JTextArea it uses either a Plainview or a WrappedPlanView. For the Plainview the painting code is:
drawLine(line, g, x, y);
y += fontHeight;
where the fontHeight is determined by using the FontMetrics.getHeight() method.
So the value is basically hard coded in the View. You could always provide a custom View for your text area, but overriding a View is generally not an easy task.
I want to reduce the height of my autocomplete field.How to go about it
heres my code
HorizontalFieldManager hfm = new HorizontalFieldManager();
LabelField lbl = new LabelField(" Name: ");
final AutoCompleteField TextField1 = new AutoCompleteField(filterLst)
{
public int getPreferredWidth()
{
return Display.getWidth()/2;
}
public void sublayout(int maxWidth, int maxheight)
{
super.sublayout(getPreferredWidth(), getPreferredHeight());
setExtent(getPreferredWidth(), getPreferredHeight());
}
};
hfm.add(lbl);
hfm.add(TextField1);
add(hfm);
The picture below is how it looks. I want it to look the same size as my editfields that have been used for other labels.
Here's my code for editfield
//Add box next to field for containing input
HorizontalFieldManager hfm1 = new HorizontalFieldManager();
LabelField lbl1 = new LabelField(" Amount: ");
final EditField TextField2 = new EditField()
{
boolean _drawFocus = false;
protected void layout(int maxWidth, int maxHeight)
{
super.layout(Math.min(maxWidth, 300), Math.min(maxHeight, 30));
}
protected boolean keyChar(char ch, int status, int time)
{
if (CharacterUtilities.isDigit(ch) || (ch == Characters.BACKSPACE))
{
return super.keyChar(ch, status, time);
}
return true;
}
protected void drawFocus(Graphics graphics,boolean on)
{
_drawFocus = on;
super.drawFocus(graphics, on);
_drawFocus = false;
}
protected void paint(Graphics g)
{
if ( _drawFocus )
{
super.paint(g);
return;
}
g.clear();
g.drawRect(0,0, 50, 50);
int oldColor = g.getColor();
g.setColor(Color.WHITE);
g.fillRect(0, 0, this.getPreferredWidth(), this.getPreferredHeight());
g.setColor(oldColor);
g.drawRect(100, 100, 50, 50);
super.paint(g);
}
};
TextField2.setBorder(BorderFactory.createRoundedBorder(new XYEdges(6,6,6,6)));
hfm1.add(lbl1);
hfm1.add(TextField2);
add(hfm1);
I would like to have the size of autocompletefield used for name same as other fields.Please help.
Thanks
One thing that's probably causing you trouble is that EditField is what people normally think of as a Field. AutoCompleteField, however, is handled more like a Manager. It wants to be a Manager, of course, because it (probably) contains an EditField, but then will also contain another child Field which shows the autocomplete options dynamically.
(Non-Manager) Field and Manager subclasses handle layout a little differently, so I found that trying to fix this with the normal getPreferredHeight() and layout() and sublayout() didn't work that well for me.
So, what I did was twofold:
First, I tried to mimic the decoration of the default AutoCompleteField with your EditField subclasses. It's not perfect. If you want them to look exactly alike, you might need to write custom paint() methods for both. You stated the problem as simply wanting to resize the fields, so I thought that was good enough.
Second, since the AutoCompleteField seems to contain a child EditField (at least logically ... I'm not sure if it's implemented that way), I decided to try to get that EditField to choose its own size, in a way that matched the normal EditFields. To do that, I controlled all fields' height by simply setting the same Font on each.
My changes to your code:
final int fontSize = 24; // pick whatever you like here
final int pad = 2;
final int margin = 2;
I removed the code in your edit field's layout() method that was attempting to control height, since ... as I said, I didn't have success setting the autocomplete field's height in a similar way. I just changed your edit field's layout() to a very standard implementation:
final EditField TextField2 = new EditField()
{
boolean _drawFocus = false;
protected void layout(int maxWidth, int maxHeight)
{
super.layout(getPreferredWidth(), getPreferredHeight());
}
Then, I set the padding on your edit field, because it looks to me like AutoCompleteField uses a pad of 2 pixels (on a 5.0 Storm2). You may not care, for this UI, but it also appears to have a margin of 2 pixels.
TextField2.setPadding(pad, pad, pad, pad);
TextField2.setMargin(margin, margin, margin, margin);
Then, I set the same font for all your fields. It doesn't have to be the default font. Just make them all the same. This step is what seemed to dictate the visible size of the rounded rectangle field drawn by AutoCompleteField ... setting the font.
Font font = Font.getDefault().derive(Font.PLAIN, fontSize);
TextField1.setFont(font);
TextField2.setFont(font);
After that, the edit fields and autocomplete fields should be a consistent height. I tested this on a 5.0 9550. Since the pad and margin values were determined experimentally, I can totally believe that those values (e.g. 2 pixels) could change on different devices. You may have to experiment a bit.
Using SWT and Java, I have a Text widget defined which is set for multi-line and wrap properties. I added a listener which will monitor any changes to the text inside this text widget, and I want the height of the widget to automatically change if the user adds a new line of text, or if the text wraps around to the next line. So, I want all of the text visible in the text widget if the user adds new text, or deletes text. Here's a sample of what I'm trying to do:
mTextValue = new Text(compositeEditor, SWT.BORDER | SWT.WRAP | SWT.MULTI);
mTextValue.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
mTextValue.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
mTextValue.addListener(SWT.Modify,new Listener()
{
protected int lines=1;
public void handleEvent(Event e)
{
Text text = (Text) e.widget;
int newlines = text.getLineCount();
if (newlines!=lines)
{
lines=newlines;
height = lines*16;
width = 240;
text.setSize(width,height);
text.getShell().pack(true);
}
}
});
Now, this seems to work ok if I add a single line of text and press the return key to add the next line. The text widget grows in height when I add lines of text, and shrinks in height when I remove lines. Just as I want. But, when I have text that wraps around and I try to add a new line, the text widget is resized in width also. I want to keep the width fixed, and only self adjust the height.
Can anyone offer a suggestion to how I can have the text widget self adjust its height to fit all of the entered text, but keep the width of the text widget always fixed at a prescribed value?
Thanks.
It may be because pack() re-computes the preferred size. I don't see any direct way to set the prefered width to constant. But you may try overriding computeSize method so that you pass fixed width as hint to super class.
i.e
public Point computeSize(int wHint,
int hHint,
boolean changed)
{
return super.computeSize(240, hHint, changed);
}