I have column headers that use a VerticalTextPainter.
If I set setCalculateByTextHeight and setCalculateByTextLength to true is resizes the columns to fit all of the text inside the cells correctly.
Sometimes the headers will have a lot of text in them so I would like them to have a maximum height.
If I stop usingsetCalculateByTextHeight and setCalculateByTextLength then the cells aren't resized at all so they just show ....
How could I go about doing this?
Update
#Override
protected void setNewMinLength(ILayerCell cell, int contentHeight) {
final ILayer layer = cell.getLayer();
final int cellLength = cell.getBounds().height;
if (contentHeight < MAXIMUM_HEIGHT && cellLength < contentHeight) {
layer.doCommand(new RowResizeCommand(layer, cell.getRowPosition(), contentHeight));
} else {
layer.doCommand(new RowResizeCommand(layer, cell.getRowPosition(), MAXIMUM_HEIGHT));
}
}
Override paintControl in NatTable
#Override
public void paintControl(final PaintEvent event) {
super.paintControl(event);
/**
* After first time rendering we stop column/row headers calculating their
* height/lengths. This allows the user to resize the column/row headers after
* the NatTable has been rendered.
*/
if (firstRender) {
columnHeaderPainter.setCalculateByTextHeight(false);
columnHeaderPainter.setCalculateByTextLength(false);
rowHeaderPainter.setCalculateByTextHeight(false);
rowHeaderPainter.setCalculateByTextLength(false);
firstRender = false;
}
}
There is no build in mechanism to specify a max height or width. Either you configure that the height should be calculated based on the content or set a fixed height.
I think you could achieve this by subclassing the VerticalTextPainter and overriding setNewMinLength() to only execute a RowResizeCommand if the contentHeight is bigger than the cellLength and the cellLength is not bigger than your maximum. And of course the RowResizeCommand should only resize to your specified maximum then.
Performing the check on any other place would probably result in an endless processing of cell height resizing.
Related
Eclipse 3.6.2 has this bug documented here
https://bugs.eclipse.org/bugs/show_bug.cgi?id=358183
There are a couple of suggested workarounds. The first one did not work for me, but the second one did.
combo.addListener(SWT.Resize, new Listener() {
#Override
public void handleEvent(final Event e) {
//We need the original text, not the displayed substring which would return methods such as combo.getText() or combo.getItem(combo.getSelectionIndex())
String text = combo.getItem((int) combo.getData("selectionIndex"));
//reset text limit
combo.setTextLimit(text.length());
GC gc = new GC(combo);
//exact dimensions of selected text
int textWidth = gc.stringExtent(text).x;
int magicConst = 14;
int comboWidth = combo.getClientArea().width - magicConst;
//In case the text is wider then the area on which it's displayed, we need to set a textLimit
if (textWidth > comboWidth) {
//find text limit - first we set it according to average char width of our text
int averageCharWidth = textWidth / text.length();
int tempLimit = comboWidth / averageCharWidth;
//sometimes on resize it can happen that computed tempLimit is greater than text length
if (tempLimit >= text.length()) {
tempLimit = text.length() - 1;
}
//then we fine-tune the limit - it must be as precise as possible
while (tempLimit > 0 && (comboWidth < gc.stringExtent(text.substring(0, tempLimit + 1)).x)) {
tempLimit--;
}
//textLimit must not be zero
if (tempLimit == 0) {
tempLimit++;
}
combo.setTextLimit(tempLimit);
}
combo.setText(text);
gc.dispose();
}
});
However, when I implement this, the widget thinks that user has changed some data (state change). This may be because of the call above to
combo.setText(text);
As our system is set up, there is a call to
org.eclipse.ui.forms.ManagedForm.isDirty()
which results in a prompt to the user to save the data every time user exits the form.
I am not familiar at all with SWT or jFace. Can anyone tell me
Is there any other way to get around the Eclipse 3.6 bug?
If not, is there a way for me to clear the dirty state of the Combo box so that the user is not prompted to save?
Thanks
Just setting the text of a Combo won't automatically set a ManagedForm to be dirty. So you must be adding a modify listener to the combo in order to do the set dirty.
You can remove the modify listener from the combo just before you do the setText and then add it back after the setText. This should stop the dirty flag from being set.
So i have this existing method on our project which defines the width and height of a widget using Dimension():
wProps.setBounds("Widget.frame.bounds", new Rectangle(WidgetStartPosition.getInstance().getStartPos(),new Dimension(getDefWidth(), getDefHeight())))
But getDefWidth() and getDefHeight() both retrieves hard coded values.
example: int height = 360; int width = 210;
public void setBounds(String key, Rectangle r)
{
if (key == null || "".equals(key) || r == null)
return;
try
{
JSONObject jObject = new JSONObject();
jObject.put(X, r.x);
jObject.put(Y, r.y);
jObject.put(WIDTH, r.width);
jObject.put(HEIGHT, r.height);
getLocalJSONObject().put(key, jObject);
}
catch (JSONException e)
{
e.printStackTrace();
}
}
because i noticed if the width and height for new Dimension() are both hard coded. Then if the width of content of the widget is more than the width defined in the new Dimension(), the content would be truncated and cut.
What i want to do is to set values in Dimension() depending on the total width and total height of whatever the content will be of the widget since the content of the widget changes every day. Is that possible?
Don't hardcode width/height values of any Swing component. Each component is responsible for determining its own size and then a layout manager can do its job when determining the size/location of each component on a panel.
What i want to do is to set values in Dimension() depending on the total width and total height of whatever the content will be of the widget
You need to override the getPreferredSize() method of your component. This is a dynamic calculation that can be done whenever a property of your component changes.
So as the content changes the preferred size can also change. Think of a component like a JLabel. As the text changes its preferred size changes.
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.
How to center JTable cells to the middle of the JTable?
I am using table to paint boxes in the table, but when resized, the cells remain left-top aligned. When the table fits the cells nicely, it is not a problem. But when I resize the window (and the table with it), it is wrong:
My question is, is it possible to make the cells appear in the middle of the table? I suppose I could use glues on sides (this is BorderLayout), but I would rather take this approach.
Since your TableCellRenderer is just painting colored blocks, you could put the table in a FlowLayout and override getPreferredScrollableViewportSize().
private static final int WIDE = 10;
private static final int HIGH = 20;
private static final int SIZE = 50;
...
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(WIDE * SIZE, HIGH * SIZE);
}
In a JTable, how can I make some rows automatically increase height to show the complete multiline text inside? This is how it is displayed at the moment:
I do not want to set the height for all rows, but only for the ones which have multiline text.
The only way to know the row height for sure is to render each cell to determine the rendered height. After your table is populated with data you can do:
private void updateRowHeights()
{
for (int row = 0; row < table.getRowCount(); row++)
{
int rowHeight = table.getRowHeight();
for (int column = 0; column < table.getColumnCount(); column++)
{
Component comp = table.prepareRenderer(table.getCellRenderer(row, column), row, column);
rowHeight = Math.max(rowHeight, comp.getPreferredSize().height);
}
table.setRowHeight(row, rowHeight);
}
}
If only the first column can contain multiple line you can optimize the above code for that column only.
Camickr's solution did not work for me at all. My data model was dynamic though - it changed all the time. I guess the mentioned solution works for static data, like coming from an array.
I had JPanel for cell renderer component and it's preferred size wasn't set correctly after using prepareRenderer(...). The size was set correctly after the containing window was already visible and did repaint (2 times in fact after some unspecified, though short time). How could I call updateRowHeights() method shown above then and where would I do this? If I called it in (overriden) Table.paint() it obviously caused infinite repaints. It took me 2 days. Literally. The solution that works for me is this one (this is the cell renderer I used for my column):
public class GlasscubesMessagesTableCellRenderer extends MyJPanelComponent implements TableCellRenderer {
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
//this method updates GUI components of my JPanel based on the model data
updateData(value);
//this sets the component's width to the column width (therwise my JPanel would not properly fill the width - I am not sure if you want this)
setSize(table.getColumnModel().getColumn(column).getWidth(), (int) getPreferredSize().getHeight());
//I used to have revalidate() call here, but it has proven redundant
int height = getHeight();
// the only thing that prevents infinite cell repaints is this
// condition
if (table.getRowHeight(row) != height){
table.setRowHeight(row, height);
}
return this;
}
}
You must iterate over each row, get the bounding box for each element and adjust the height accordingly. There is no code support for this in the standard JTable (see this article for a solution for Java ... 1.3.1 =8*O).