I have a JTabbedPane with several tabs. Inside each tab I have a JScrollpane with a jtree inside. Each jtree node is another panel, containing other components, returned by a function. This works fine.
The problem is this:
On first show of the trees (all of them) the root nodes do not show completely. Only the top half shows. when double-clicked they show correctly if they have child nodes, if they don't nothing happens.
I can't find a way to show the nodes correctly the first time. I tried invalidate, validate paint, repaint, etc with several combinations.
Nothing works.
Found it!
ScrollPaneContainigTheTabel.setColumnHeader(new JViewport()
{
/**
*
*/
private static final long serialVersionUID = 1L;
#Override public Dimension getPreferredSize()
{
Dimension d = super.getPreferredSize();
d.height = WHATEVER_HEIGHT_IS_NEEDED;
return d;
}
});
Forcing the Table Header height solved the problem...
Now it recalculates the sizes correctly...
WHATEVER_HEIGHT_IS_NEEDED can be an int or a calculated value if you use (as i do) html to set more than one line in the header...
Related
I have a List of JPanel and each element of a list have 10 JPanel elements inside it which contains a picture. (as the Picture)
I set Float layout for aligning them horizontally one after another. (Each row JPanel elements)
I put each element of this list on another outer JPanel vertically and everything is ok. (Each Vertical JPanel)
now I want to put the above label F1 till F10 exactly at the center of the first now elements ? how am going to do that ? any recommendation ?
Take note I can't use TitledBorder (with title and no border) for the first row elements because I have a selection function for each element and If I do this, It select the whole first row element (element + titledborder) which is pretty ugly and not similar to the other rows ?
do you hae any solution ?
Make the top row a JPanel having the default layout, FlowLayout. Add ten instances of a custom JLabel in which you override getPreferredSize() to return the nominal picture width and a height no less than that returned by the parent's implementation.
private static final int W = 50;
private static class MyLabel extends JLabel {
public MyLabel(String text) {
super(text);
this.setHorizontalAlignment(CENTER);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(W, super.getPreferredSize().height);
}
}
Im trying to learn Java and using the GUI as an upgrade to the "booring" C\C++
I had two panels, one of them with an input form, and one of them with a table which suppose to show the things I load from the input form.
But no idea why, the table expands and has a border line, moreover, it has a fixed size and whenever I expand the window, the table stays the same.
The "mainFrame" (the file that calls the c'tor) just initiate the table and add it to the layout so im sure its not happening there...
I've added the JTable class code and a picture showing whats happening
The link if it shows too small : http://oi62.tinypic.com/ok4hs5.jpg
And the code :
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class TableOutput extends JPanel {
private static final long serialVersionUID = 1L;
private JTable jt;
public TableOutput() {
String[] columns = {"Product ID" , "Date" , "Name" , "Address" , "Status"};
String[][] data = {};
jt = new JTable(data,columns);
jt.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
JScrollPane jsp = new JScrollPane(jt, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
add(jsp);
}
But no idea why, the table expands and has a border line, moreover, it has a fixed size
size - Do System.out.println(table.getPreferredScrollableViewportSize()). This is the method the scroll pane calls to get the preferred size for the table view. You will see that the default it 450x400. You can change it by overriding getPreferredScrollableViewportSize() on the table.
JTable table = new JTable() {
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(300, 300);
}
};
border - that's not the table border. It's actually the scroll pane border.
whenever I expand the window, the table stays the same.
JPanel has a default FlowLayout, which will always respect the preferred size of the contained component. If you want the table/scrollpane to stretch with the panel, use a layout manager like BorderLayout which will disregard the preferred size and stretch to fit. Keep in mind that if the panel is contained by a container with the FlowLayout, you will still get your current result. If the panel is just being added the frame with its default BorderLayout, then you should be fine. See more at How to use Layout Managers
Note: You may find out though that if you want to set the layout the BorderLayout, the preferred size of the scroll pane will have no effect. This will leave you will the same result - the table will big with empty rows and the border.
I'm arranging images in a grid with MigLayout. I could get the width to take the whole space available in the column, but then I want the height to grow accordingly so the proportion of the image still fixed.
What is the best approach for this? Could I do that with an expression in the constraint or I have to override the getPreferredSize()?
Thanks!
After a lot of researching, I realize that there is no nice way of doing this with Swing. The problem is not only coming from MigLayout but also from layouts like ScrollPaneLayout, which assumes that the preferred height will remain the same after a different effective width (which is not the preferred width).
There are two options:
1) Currently, I'm doing my own implementation of MigLayout with an aspect ratio component constraint. You can download it from here:
https://github.com/lqbweb/miglayout-aspect
So far, it works with shrinking and growing X in a simple grid case with 1 component / cell. I still have to test with spanning, flowing in the cell and docking..... I'll keep that repository updated and any help is well welcome.
As you will probably use it as a view on a ViewPort, you will have to hack a bit the getPreferredSize of the view if you use it with the Scrollable.getScrollableTracksViewportWidth() returning true, so it doesn't return the real preferred height but the one that matches the width. In my code there is a getter for the grid, and the grid has a function to return a preferred height for a given width.
2) Keeping the current implementation of MigLayout untouched (4.2 at the time of this answer), I only found one way to achieve this: by adding a callback to the layout and implementing getSize() method with something like this:
migLayout.addLayoutCallback(new LayoutCallback() {
/**
* This is run before the layout starts laying out
*/
#Override
public BoundSize[] getSize(ComponentWrapper comp) {
if(comp.getComponent() instanceof DCMImageWrapper) {
DCMImageWrapper img=(DCMImageWrapper) comp.getComponent(); //this is the BufferedImage embedded in a JLabel
int calculatedHeight=img.getHeightFor(comp.getWidth());
UnitValue maxHeight=new UnitValue(calculatedHeight);
BoundSize height=new BoundSize(maxHeight, maxHeight, maxHeight, null);
return new BoundSize[]{null, height};
} else {
return null;
}
}
private double getCurrentAspect(ComponentWrapper comp) {
if(comp.getWidth()==0 || comp.getHeight()==0) return 0;
double currentAspect=comp.getWidth()/(double)comp.getHeight();
return currentAspect;
}
/**
* Check if the aspect still valid
*/
#Override
public void correctBounds(ComponentWrapper comp) {
if(comp.getComponent() instanceof DCMImageWrapper) {
DCMImageWrapper img=(DCMImageWrapper) comp.getComponent();
double currentAspect=getCurrentAspect(comp);
double origAspect=img.getDCMImage().getAspect();
double currentError=Math.abs(origAspect-currentAspect);
if(currentError > img.getDCMImage().getAspectError()) {
//recalculate layout
revalidate();
}
}
}
});
and then, adding the component like:
CC constraints=new CC();
constraints.shrinkX(100);
constraints.minWidth("1");
constraints.minHeight("1");
add(tmpImg, constraints);
But, you will have to add and keep updated a layout constraint (LC) to set manually the preferred size of the layout, as after the callback it gets biased.
I am writing a small POS application, which shows a JTable with ticket information inside its cells. CellRenderer is a class which extends JPanel and implements TableCellRenderer, and contains a few JTextFields showing basic information (quantity, descripcion, price).
Also, I have another class extending JPanel and implementing TableCellEditor, which is used as CellEditor. This class contains more JTextFields and also a few jButtons.
What I need is simple: when I edit any cell by clicking with the mouse (or touching the screen, which is, as far as I know, the same event), dynamically increase the height of the cell I'm going to edit, so it can show all the components inside the editor. And when I finish editing, return cell height to its previous value.
Any idea about doing it?
Thanks in advance. :-)
CellRenderer is a class which extends JPanel and implements TableCellRenderer, and contains a few JTextFields showing basic information (quantity, descripcion, price). Also, I have another class extending JPanel and implementing TableCellEditor, which is used as CellEditor. This class contains more JTextFields and also a few jButtons.
better could be to create popup window (JDialog) based on event from JPopupMenu,
Dynamically Increase JTable row height when editing, and decrease when finish edit
don't confused users and wrong concept could be caused by jumping JTables row on the screen
What I need is simple: when I edit any cell by clicking with the mouse (or touching the screen, which is, as far as I know, the same event), dynamically increase the height of the cell I'm going to edit, so it can show all the components inside the editor. And when I finish editing, return cell height to its previous value.
don't do that, but have to override, is possible by
DefaultCellEditor#setClickCountToStart(int) for TableCellEditor
start, stop and cancelEdit for CellEditor
have to notify or re_Layout JTable, the same on stop and cancelEdit
Not an answer to how-to-adjust-rowHeights, but for an alternative mentioned in my comment: "oversize" the editorComponent only instead of updating the complete rowHeight (which I think would be too irritating to users, but up to you to decide, of course :)
// fake a bigger editing component
JTextField oversized = new JTextField() {
#Override
public Dimension getPreferredSize() {
Dimension dim = super.getPreferredSize();
dim.height *= 5;
return dim;
}
};
TableCellEditor editor = new DefaultCellEditor(oversized);
JTable table = new JTable(new AncientSwingTeam()) {
#Override
public boolean editCellAt(int row, int column, EventObject e) {
boolean result = super.editCellAt(row, column, e);
if (result) {
// adjust cell bounds of the editing component
Rectangle bounds = getEditorComponent().getBounds();
bounds.height = getEditorComponent().getPreferredSize().height;
getEditorComponent().setBounds(bounds);
}
return result;
}
#Override
public void removeEditor() {
int editingColumn = getEditingColumn();
super.removeEditor();
if (editingColumn >= 0) {
// cleanup
repaint();
}
}
};
table.getColumnModel().getColumn(0).setCellEditor(editor);
Didn't try it, but I would say implementing MouseListener's mouseClicked() method is the way to go. Keep track of whether the cells height was already increased, and change the height accordingly.
Since MouseListener is an interface, CellRenderer could implement this interface too, keeping all cell-behavior in one class.
I am having a problem with displaying my SVG drawing in an diagramming application. The canvas takes the size of its parent component, instead of the document it contains. Documents that are bigger than this size are not completely rendered.
Case
I have a drawing that is, for example, 621x621 pixels.
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" contentScriptType="text/ecmascript" zoomAndPan="magnify" contentStyleType="text/css" preserveAspectRatio="xMaxYMax slice" version="1.0">
<rect x="50" y="50" fill="white" width="20" height="20" stroke="black" stroke-width="1"/>
<rect x="600" y="600" fill="blue" width="20" height="20" stroke="black" stroke-width="1"/>
</svg>
It has no viewBox because it is created dynamically. When I'm creating the document I don't have the size.
I have a JSVGCanvas inside a JSVGScrollPane, the parent of the scrollpane is smaller then the document, lets say its 500x500 pixels.
Expected behaviour
When you launch the application the part of the drawing that fits in the 500x500 is visible. The underlying document is bigger so there are scrollbars that allow me to scroll 121px to the left and to below.
When you increase the size of the frame, more and more of the drawing becomes visible. When you increase it to be greater than 620x620px the scrollbars can disappear completely.
If you make the panel smaller then the document again, the scrollbars reappear.
Encountered behaviour
When you launch the application the part of the drawing that fits in the 500x500 is visible. No scrollbars are visible.
When you make the panel bigger, the canvas is increased (its background color) but the drawing is not extended to the part that's outside the initial 500x500px.
When you make the panel smaller, lets say to 400x400, scrollbars do appear, but only allow me to scroll 100px. So the canvas still is the initial 500x500 instead of the desired 621x621.
Example
The encountered behaviour can be reproduced with the ScrollExample on the Batik repository and the SVG-file i've added above. The example uses a fixed size of 500x500px.
If you'd add background colors to the canvas and scrollpane, the entire frame is blue. So while the canvas does increase in size, it does not draw anything beyond its initial size.
canvas.setBackground(Color.blue);
scroller.setBackground(Color.red);
I could reset the document when I've re-sized the panel. This makes it redraw the visible part of the drawing, but the scrolling is still not working as expected, since the canvas is still just the size of the visible portion instead of the size of the document. You can test this by adding this listener to the frame (or any other panel I suppose).
class ResizeListener implements ComponentListener {
JSVGCanvas canvas;
URI url;
public ResizeListener(JSVGCanvas c, URI u) {
canvas = c;
url = u;
}
#Override
public void componentResized(ComponentEvent arg0) {
canvas.setURI(url.toString());
// Calling invalidate on canvas or scroller does not work
}
// ...
};
I have read that I should have a viewBox, but my document is recreated often (based on a modelchange-event) and when I'm creating the document, i don't know how to get the viewBox. SVGDocument.getRootElement().getBBox(); usually gives me null. There are supposed to be fallbacks in the Batik code when no viewBox is given, so I hope this is optional. Also when I'm panned somewhere, it should keep this panning if I change the document.
I hope i'm making my problem clear. Am I expecting too much of the JSVG-classes when I expect them to provide my desired behaviour out of the box or am I missing something here? Could someone please guide me towards a solution?
I think I might have found a solution. Instead of messing with viewBox I need to set the height and width of the document. With the size set, no viewBox is necessary and the scrollbars work as expected. If I do set a viewbox, the canvas keeps scaling the image to make it fit.
Now, for updating the size I use this whenever I change the dom that could have influence on the size.
static BridgeContext ctx = new BridgeContext(new UserAgentAdapter());
static GVTBuilder builder = new GVTBuilder();
private static void calculateSize(SVGDocument doc) {
GraphicsNode gvtRoot = builder.build(ctx, doc);
Rectangle2D rect = gvtRoot.getSensitiveBounds();
doc.getRootElement().setAttributeNS(null,
SVGConstants.SVG_WIDTH_ATTRIBUTE, rect.getMaxX() + "");
doc.getRootElement().setAttributeNS(null,
SVGConstants.SVG_HEIGHT_ATTRIBUTE, rect.getMaxY() + "");
}
I do this outside of the UpdateManager thread and after the dom modification I use JSVGCanvas.setSVGDocument(). When I tried to do this via the UpdateManager it only updated the first change. There is probably a fix for this with the right initialization of the updatequeue, but since I change a lot of the document, I could just as well start fresh every time.
I am left with one minor issue. Whenever i set a new document, the scroll position is reset. I tried getting the transformation before the manipulation and reapply it afterwards, but this doesn't seem to work.
Edit+:
I managed to fix this minor issue by replacing the root node of the document rather than replacing the entire document. The canvas is set with the documentstate ALWAYS_DYNAMIC. The changes in the document are applied immediately, including the new size of the root node (set as described above). But because the document is not entirely replaced the scroll state is kept.
The canvas is only ready for modification of the dom after it has finished rendering a document. I used the SVGLoad-listener to detect this.
class Canvas extends JSVGCanvas implements SVGLoadEventDispatcherListener {
public Canvas() {
super();
setDocumentState(ALWAYS_DYNAMIC);
addSVGLoadEventDispatcherListener(this);
}
/**
* Indicatates whether the canvas has finished its first render, the
* canvas is now ready for modification of the dom
*/
private boolean isReadyForModification = false;
/**
* Renew the document by replacing the root node with the one of the new
* document
*
* #param doc The new document
*/
public void renewDocument(final SVGDocument doc) {
if (isReadyForModification) {
getUpdateManager().getUpdateRunnableQueue().invokeLater(
new Runnable() {
#Override
public void run() {
// Get the root tags of the documents
Node oldRoot = getSVGDocument().getFirstChild();
Node newRoot = doc.getFirstChild();
// Make the new node suitable for the old
// document
newRoot = getSVGDocument().importNode(newRoot,
true);
// Replace the nodes
getSVGDocument().replaceChild(newRoot, oldRoot);
}
});
} else {
setSVGDocument(doc);
}
}
#Override
public void svgLoadEventDispatchCompleted(SVGLoadEventDispatcherEvent e) {
isReadyForModification = true;
}
// ...
}