Could someone tell me how to implement RichTextFX CodeArea with line numbers section extended till the end of the area?
This is how it looks like now:
I don't need line numbers after line 12 but I would like to see this grey bar to fill the entire text area.
Something like here:
P.S. I'm not sure if this is even possible.
I know this is a rather old question, but since I had the same problem, let me share the solution I came up with.
What I did is to smuggle in a rectangle and make sure it is the bottom-most element (i.e. basically part of the background). However, there are a few gotchas when doing this, because the underlying CodeArea is not aware of our new node. If you just insert the rectangle, it might get removed when the CodeArea decides to rebuild the nodes. And getting the right width is a bit tricky because the width of line numbers can basically change at any time and the line-number labels themselves fade in and out of existence whenever you scroll.
So, in order to address these issues, my code sits in the layoutChildren() method and is thus called whenever the nodes in the editor have changed. First we check that the rectangle is actually there as the bottom-most node or insert it if missing. Second, we set the width of the rectangle to the width of the first visible line-number label (which might fail if there are no paragraphs at the moment).
The code itself here is in Scala, but probably easy enough to be quickly adapted to Java.
class MyCodeArea extends CodeArea {
protected val gutterRect = new Rectangle()
gutterRect.heightProperty.bind(this.heightProperty)
gutterRect.getStyleClass.add("lineno")
override protected def layoutChildren(): Unit = {
try {
val children = getChildren
if (!(children.get(0) eq gutterRect))
children.add(0, gutterRect)
val index = visibleParToAllParIndex(0)
val wd = getParagraphGraphic(index).prefWidth(-1)
gutterRect.setWidth(wd)
} catch {
case _: Throwable =>
}
super.layoutChildren()
}
}
Unfortunately, the colour of the rectangle must be assimilated manually. The reason is that the Labels used for line numbers use -fx-background-color, whereas the Rectangle uses -fx-fill. Hence, just setting the same CSS class "lineno" (as I did in my code above) does little to get the colour right. But it allowed me to put both into the same CSS class and therefore have one place where I can change it:
.lineno {
-fx-fill: ivory; // or whatever colour you like
-fx-background-color: -fx-fill;
}
Related
As succinctly as I can manage: Given that I need the layout information of a node (the actual height/width of a node as rendered) to compute my animation, how can I get that information before javafx draws a frame with it?
A little bit longer explanation:
I've got a TreeItem that has child items appearing in it (at the front). What I'd like to have is an animation to cause all existing children to slide down to make room for the new item which would slide in. Each child tree-items contents are different and only known at run-time, meaning the height of each child tree item cannot be expressed as a constant.
This got me writing code along these lines:
groupController.groupTreeItem.getChildren().addListener(
new ListChangeListener<TreeItem<Node>>() {
#Override public void onChanged(Change<? extends TreeItem<Node>> c) {
while(c.next()){
if ( ! c.wasAdded()){
continue;
}
TreeItem newItem = c.getAddedSublist().get(0)
new Timeline(
new KeyFrame(
seconds(0),
new KeyValue(view.translateYProperty(), -1 * newItem.getHeight())
),
new KeyFrame(
seconds(1),
new KeyValue(view.translateYProperty(), 0)
)
);
}
}
}
);
the issue here is that as when a treeItem is added to another, its components aren't laid out by the time the invalidation event is fired, meaning newItem.view.getHeight() returns 0.
My next thought was to then have the animation performed as a reaction to both a change in the list content and a sequential change to the height property, (which got me to write some really hideous code that I'd rather not share --listeners adding listeners is not something I really want to write). This almost works, except that javaFX will draw a single frame with the height property set but without the animations translation applied. I could hack down this road further and try to work something out with opacity being toggled and jobs being enqueued for later, but I figured that this would be the path to madness.
I'm wondering if there's some pseudo-class foo or some clever use of a layout property I could use to help me here. I've been poking around at various combinations of various properties, and haven't gotten anywhere. It seems that as soon as the component has a height, it is rendered, regardless of any listeners you put in or around that height assignment.
Any help much appreciated!
have you tried, overriding this
#Override
protected void updateBounds() {
super.updateBounds();
}
I need to add break line in some legend in JFree Chart.
I have some legends with 316 characters and need to break every 80.
Finally, I'll have 4 lines.
Anyway, I tried with "\n", "\u2424" and "
". It did nothing.
(From http://www.jfree.org/forum/viewtopic.php?f=3&t=10226 & http://www.jfree.org/forum/viewtopic.php?f=3&t=22417)
The only solution I could find (but I wished it could be avoided, since I want it to be dynamically done) is to fix a width for each legend, so it should break as I need to.
Edit : that even didn't work.
I'm using jFree Chart 0.9.20
EDIT
For the moment, with a small legend, that's what I have :
It's fine but when I have my long legends :
For that last picture, I logged my legend and break lines are here, but they don't show up with jFree Chart.
Two alternatives to consider: Given an abbreviated legend display string,
Use setLegendItemToolTipGenerator() to display the full, unbroken string as a tool tip.
renderer.setLegendItemToolTipGenerator(
new StandardXYSeriesLabelGenerator("Legend {0}"));
Use addChartMouseListener(), shown here, and forward mouse moved events over the legend to an adjacent text component.
Alright, I made it work as my client wanted.
First, you need to make a new kind of Legend, for example named MyLegend (but please, don't name it like that in the real world).
That class needs to extend Legend and implement Serializable, the same way StandardLegend does.
To be honest, I even copied/pasted the whole StandardLegend in MyLegend.
Then, you can modify the standard legend to your custom one.
For my needs, I changed :
draw() for the height and width calculation of the whole Legend group
drawSeriesElements() to split the legend's label and draw every lines one under another.
// Multi line management for Legend
String[] multiline = item.getItem().getLabel().split(System.getProperty("line.separator"));
for(int j = 0; j<multiline.length; j++) {
RefineryUtilities.drawAlignedString(multiline[j], g2,
(float) item.getLabelPosition().getX(), (float) item
.getLabelPosition().getY() + g2.getFontMetrics().getHeight()*j, TextAnchor.CENTER_LEFT);
}
createDrawableLegendItem() to calculate each item width and height.
Since, now legends are multiline, each line of one item doesn't have the same width than others. We need to find the longest one to define the item's real width.
Same goes for height. Now it's multiline, so it needs to calculate how many lines it got to know the item's real height.
Optionally, you could change drawLegendTitle() to make it multiline too.
When that class is configured as you want to, you need to apply it on your chart.
So, you do as usual :
JFreeChart chart = new JFreeChart(...);
chart.set ... // apply your series and options
MyLegend legend = new MyLegend();
legend.set... // apply your legend options if applicable
chart.setLegend(legend);
That's it.
Result :
Before any one suggests HTML, I explain later why thats not an option here. I have a table that contains a column with text cells in it. I need to be able to highlight some of the text in each cell. So for example if the cell contained "cat foo dog"... I might want to highlight foo.
My current method is to use a custom TableCellRenderer that puts html into a JLabel component that gets rendered and for a time it was good. Then I noticed that when the text in the cell became too long to fit in the column width it just truncated the text without the normal "..." that happens normally in this case. Thus users didnt know there was more text they were not seeing. The other problem was that if the original text itself contained HTML, which in my case it does at times, the cell would not render correctly. I know I could just escape the html but I would still have the prevous problem.
If I use a component other than a jlabel then it makes my table's cells look strange. Does any one have any suggestions? Thanks
Well, here is a solution.
In short, you can subclass JLabel to draw the highlight manually. Override the paintComponent method to do the actual drawing and use FontMetrics to calculate where the highlighted region should be drawn.
Here is that answer in excruciating detail:
Basically, you can make a subclass of JLabel that can highlight stuff. I would do that like this; you may want to do it somewhat differently:
Add a method that tells the label which part to highlight. This could be something like this, assuming you just need one highlighted region:
public void highlightRegion(int start, int end) {
// Set some field to tell you where the highlight starts and ends...
}
If you need multiple regions, just have an ArrayList instead of a simple field. A method for dehighlighting would probably be useful too.
Now, you need to override the paintComponent method of JLabel. Here you need to do several discrete steps, which you may want to organize in different methods or something. For simplicity, I'll put it all in the paint method.
#Override
protected void paintComponent(Graphics g) {
...
First, you need to figure out the physical dimensions of the highlight, which you can do using the nice FontMetrics class. Create the FontMetrics class for the Font you're using.
FontMetrics metrics = new FontMetrics(getFont());
Now you can get all the information you need to create a rectangle that will be the highlight. You'll need the starting position, the height and the width. To get this, you'll need two substrings of the JLabel's text as follows:
String start = getText().substring(0, startOfHighlight);
String text = getText().substring(startOfHighlight, endOfHighlight);
//You may also need to account for some offsets here:
int startX = metrics.stringWidth(start);
int startY = 0; //You probably have some vertical offset to add here.
int length = metrics.stringWidth(text);
int height = metrics.getHeight();
Now you can draw the highlighted region before drawing the rest of the label:
g.fillRect(startX, startY, length, height);
super.paintComponent(g);
}
Of course, if you want the highlight to span multiple rows, that will require more work.
If you were wondering, I have actually written something like this before. On a whim, I decided to write my own text area type component from a JPanel, and this was basically the way I handled highlighting. Reinventing the wheel may be stupid in an actual project, but it does teach you random stuff that may come in useful...
Can't resist to throw the SwingX renderer decoration mechanism into the ring: its way to solve the requirement is to implement a Highlighter doing it. Which in fact is already done (though not yet in the officially supported) but hidden in the SwingLabs-Demos project, named X/MatchingTextHighlighter (you would need both) and recently fixed to cope with icons, RToL-ComponentOrientation, alignment, ellipses ..
Thats a great answer, and probably the best solution. But an alternative that some might find simpler is to use a JTextfield instead of a JLabel for rendering then you can use JTextfields highlighting capabilities i.e
void highlightWhitespaceText(JTextField text)
{
text.setHighlighter(AbstractTableCellRenderer.defaultHighlighter);
try
{
Matcher m = AbstractTableCellRenderer.whitespaceStartPattern.matcher(text.getText());
if (m.matches())
{
text.getHighlighter().addHighlight(m.start(1), m.end(1), AbstractTableCellRenderer.highlightPainter);
}
m = AbstractTableCellRenderer.whitespaceEndPattern.matcher(text.getText());
if (m.matches())
{
text.getHighlighter().addHighlight(m.start(1), m.end(1), AbstractTableCellRenderer.highlightPainter);
}
}
catch (BadLocationException ble)
{
//
}
}
You can change the properties of a JTextfield so it looks like a jLabel in other respects.
I'm trying to make a scroll panel that has relative size parameters. But the ScrollPanel.setSize(String, String) function is impossible to work with if you have int values such as those returned by Window.getHeight.
When I try ScrollPanel.setSize("100%", "150px"); it doesn't change the height of the scroll panel and instead uses the default. Any help would be appreciated.
According to the GWT doc for [ScrollPanel][1], they seem to be pretty strict about using the width in absolute and not relative CSS units.
Thus the problem may be with the "100%" parameter.
[1]: http://google-web-toolkit.googlecode.com/svn/javadoc/1.5/com/google/gwt/user/client/ui/ScrollPanel.html#setSize(java.lang.String, java.lang.String)
I'm not sure if it's possible to do with the height, but what worked for me with the width was to first set an arbitrary width, then get the element and set the the width property.
ScrollPanel myScrollPanel = new ScrollPanel();
myScrollPanel.setSize("2112px", "150px"); // Arbitrary width.
myScrollPanel.getElement().getStyle().setProperty("width", "100%"); // or "auto"
Hope this works for you (although you asked this 5 years ago, so you're probably not too worried about it anymore)!
Copying my answer from here: How to use ScrollPanel with relative size
==================================================================
First, ScrollPanel is something not acting as other widget for reason I don't know why. Cannot set relative size (50%), and if I give it some style, it's lost somewhere and cannot be found from page.
My solution is to use a ResizeLayoutPanel. Andrei suggested using something ProvidesResize but requires the provide / require resize chain remain unbroken, which can be very tricky. I found this ResizeLayoutPanel "ProvidesResize to its one child, but does not RequiresResize", which is the perfect candidate for the root panel of my composite. Then, I just extend the ScrollPanel to resize itself in the "onResize" method whenever it's called by the parent ResizeLayoutPanel.
Still no answer to my first question: by ScrollPanel behave like this in the first place? I tried to find answer in its source code but was not successful (though I didn't spend enough time studying the source code).
public class My100PctScrollPanel extends ScrollPanel {
#Override
public void onResize() {
// Window.alert("on resize");
this.setWidth(this.getParent().getOffsetWidth()+"px");
this.setHeight(this.getParent().getOffsetHeight()+"px");
super.onResize();
}
}
........
compositeRoot = new ResizeLayoutPanel();
........
scrollPanel = new My100PctScrollPanel();
compositeRoot.clear();
compositeRoot.add(scrollPanel);
I have to use a GUI Element that draws a picture at a specific screen position.
If the user selects this picture there is a border drawn around the Image.
Now we want to include another border that identifies pictures with a specific value for the user.
At the moment the Element looks at his internal state if it is selected and then decides how to draw itself.
graphic.drawImage(icon, x, y, null);
if (selected) {
drawBorder();
}
I don't like the idea of adding another if else to this drawing method.
I thought about creating a new class that inherits the behavior of the element and overwrites the draw method but that means duplicating the whole selected code in every inherited class.
Is there a nice possibility so solve this problem without creating a subclass?
Since you tagged this with design-patterns and you seem to be looking for a pattern-oriented approach, I'd suggest taking a look at the state pattern. The example on the wikipedia page even mentions keeping state while drawing a GUI. Unfortunately, this would mean you'd have to create another class with subclasses and overridden methods.
Is this going to be something that is likely to change? I.e. do you realistically think you're going to be adding new behavior to the drawing (e.g. if the user double clicks, draw a different type of border; if the user right clicks, change the color of the border), or is this it? If you see more behavior being added, I think going ahead and taking a more OO approach is wise. If it's just these two cases, I'd say just add and else if statement.
What do you have against if-else?
It makes less sense to me to create a whole new object for the selected item than to check a flag in the drawing function.
one possibility is to allow your drawBorder() method to take parameters:
private void drawBorder(boolean isSelected, boolean hasSpecialValue);
this method can determine which type of border to draw.