I'm trying to reproduce a piechart/ringplot produced by a different tool. Everything is fine except for the legend. I need to put values inside the graphical part of each LegendItem:
Image
I think that I have the outlines of a solution but would like you experienced jfreecharters to ack that I'm on the right track. I'm wondering if this couldn't be done in an easier way?
One way could be to subclass LegendTitle and override createLegendItemBlock(..). Copy most of the content but instead of contructing a LegendGraphic, construct a subclassed LegendGraphic which knows how to handle text inside the shape.
Any comments would be very welcome.
I implemented the solution outlined in the question and it works fine. If anyone else should come across the problem, here's the subclassed LegendGraphic which handles text. The subclassed LegendTitle and overridden createLegendItemBlock(..) method are straightforward.
class CustomLegendGraphic extends LegendGraphic {
String label;
public CustomLegendGraphic(Shape shape, Paint fillPaint, String label) {
super(shape, fillPaint);
this.label = label;
}
#Override
public Object draw(Graphics2D g2, Rectangle2D area, Object params) {
Object result = super.draw(g2, area, params);
area = trimMargin(area);
Point2D location = RectangleAnchor.coordinates(area, this.getShapeLocation());
TextBlock textBlock = TextUtilities.createTextBlock(label, getItemFont(), Color.white);
textBlock.draw(g2, (float)location.getX(), (float)location.getY(), TextBlockAnchor.CENTER);
return result;
}
}
Related
I'm using GraphStream to show a map of an area and I've tried to inherit from the default MouseManager DefaultMouseManager and to override the mouseClicked method so that when clicking on a node the following will happened:
node's color will change.
node's label will show.
node's data will show in terminal.
I do know that the method works because the node's data does get printed to terminal, but I think some other mouse event repaint the node and rehide the label so they doesn't change when clicking on a node.
here is my MouseManager's code:
public class CustomMouseManager2 extends DefaultMouseManager {
protected View view;
protected GraphicGraph graph;
private GraphicElement focusedNode;
#Override
public void init(GraphicGraph graph, View view) {
super.init(graph, view);
.
.
.
}
#Override
public void mouseClicked(MouseEvent e) {
GraphicElement currentNode = view.findNodeOrSpriteAt(e.getX(), e.getY());
if(currentNode != null){
OGraph graph = OGraph.getInstance();
Random r = new Random();
currentNode.setAttribute("ui.style", "fill-color: red; text-mode: normal;");
ONode oNode = graph.getNode(Long.parseLong(currentNode.getLabel()));
System.out.println(oNode.toString());
}
if(focusedNode!= null)
focusedNode.setAttribute("ui.style", "fill-color: black;size: 10px, 10px; text-mode: hidden;");
focusedNode = currentNode;
}
}
I've tried to check what methods from the base class DefaultMouseManager are called after my mouseClicked is called so I could override them too, but there was to many of them to follow.
Is there an elegant way to make sure my changes will execute after all other method from the base class?
Is there an elegant way to make sure my changes will execute after all other method from the base class?
Read the documentation and look at the code in DefaultMouseManager. I googled DefaultMouseManager, looked at the documentation, went through the inheritance of the different interfaces until I got to MouseListener, which describes the order of operations. Then I looked at mouseClicked and mouseReleased since they would be called last, mouseClicked is empty so that leaves mouseReleased and the methods that are called in it.
So, something similar to this question has happened, the mouseClicked() method was called twice.
In my code, I repaint black the previous node and hide its label after a new node is clicked. And for that reason, when the mouseClicked() method was called twice then the first call changed the node`s appearance and the second one changed it back.
In that case, an easy fix will be to check if the previous node and current node are the same. replace this if(focusedNode!= null) with this
if(focusedNode!= null && focusedNode != currentNode)
but a more straightforward solution will be to understand why the method is been called twice.
My guess is that it has something to do with the inheritance but I'm not sure.
I'm developing an Android application using osmdroid and osmbonus pack libraries which allows the user to drag and drop icons to the map from a menu.
The application is intended to allow the user to "save the map", so i'm trying to manage how to save all the dragged markers in a kml document, and than loading it when necessary.
I've tried following the 13.3 tutorial https://github.com/MKergall/osmbonuspack/wiki/Tutorial_4 , but i still can't figure it out, so i'm probably missing something.
I created a class for the insert of the markers in the map, with this method:
public void insertIcon(int image) throws IOException {
marker = new Marker(map);
point = new GeoPoint(currentLocation);
marker.setPosition(point);
marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
map.getOverlays().add(marker);
map.invalidate();
applyDraggableListener(marker);
marker.setIcon(activity.getDrawable(image));
}
And then once the marker is dragged in a certain position, i add it to the kml structure:
...
public void onMarkerDragEnd(Marker marker) {
GeoPoint geopoint = marker.getPosition();
//poiMarker.setDraggable(false);
Utilities.kmlDocument.mKmlRoot.addOverlay(marker, Utilities.kmlDocument);
}
...
At this point, i don't know how to assign to that specific marker its specific style, which is basically just the icon.
I've made several tests inside the MyKmlStyler, but the main point of the problem is in fact that i don't know how distinguish between each kmlPlacemark.
Inside the method onPoint of MyKmlStyler i put a println and obviously all the placemarks have the same style.
#Override
public void onPoint(Marker marker, KmlPlacemark kmlPlacemark, KmlPoint kmlPoint) {
System.out.println(kmlPlacemark);
}
The only thing i'm able to do is giving a unique style to all the markers dragged.
I've already tried with putStyle and the other ways described in the tutorial, but as i've already said, most likely i'm missing something.
My goal is to give each kmlPlacemark a different style according to what the real icon of the marker the user dragged is, all inside the same kmlDocument.
Edit
I thought i managed to find a solution this way:
public void onMarkerDragEnd(Marker marker) {
/*GeoPoint geopoint = marker.getPosition();
poiMarker.setDraggable(false);
*/
KmlDocument mKmlDocument = new KmlDocument();
KmlPlacemark p = new KmlPlacemark(marker);
Style s = buildStyle();
p.mStyle = mKmlDocument.addStyle(s);
mKmlDocument.mKmlRoot.add(p);
mKmlOverlay = (FolderOverlay) mKmlDocument.mKmlRoot.buildOverlay(map, null, null, mKmlDocument);
Utilities.kmlDocument.mKmlRoot.addOverlay(mKmlOverlay, Utilities.kmlDocument);
}
private Style buildStyle(){
Drawable defaultMarker = AppCompatResources.getDrawable(activity, R.drawable.person);
Bitmap defaultBitmap = ((BitmapDrawable) defaultMarker).getBitmap();
return new Style(defaultBitmap, 0x901010AA, 3.0f, 0x20AA1010);
}
but still, no style is applied to the markers, so the icon shown is the default one, not the chosen one.
Note: Utilities.kmlDocument is where i store all the map markers so it is different from mKmlDocument
Basically, your root cause issue if that you try to rely on markers to build your KML document.
You should handle your own "model", and from that model, build markers as needed, and build KML document when needed.
Your "model" can probably be something as simple as an arraylist of objects with: a GeoPosition, and a "type". Depending on this type, you will be able to create markers with various icons, and KmlPlacemarks with various styles.
I have an SWT table that is wrapped with a JFace TableViewer.
My requirements are:
Decorate the column image with the decorators as they are defined in the workbench decorator manager
Decorate the text of the columns with different colors
I was able to #1 by extending DecoratingLabelProvider and implementing ITableLabelProvider. I passed it my original TableLabelProvider and the workbench decorator manager, and I got icons with decorators.
Then I started to work on #2. I asked this question here and was told that IStyleLabelProvider (what I was trying to use for the colored text) was incompatible with ITableLabelProvider. So I switched to using a ColumnLabelProvider that implements IStyledLabelProvider.
However, now I am stuck. These 2 requirements seem to be mutually exclusive. I cannot extend both ColumnLabelProvider and DecoratingLabelProvider. When I tried to simply pass in the workbench decorator manager to the ColumnLabelProvider like this, but it did not decorate the image at all. Did I pass it in wrong, or will that only work in a DecoratingLabelProvider? What else can I try?
public Image getColumnImage(final Object element, final int columnIndex) {
if (columnIndex == MY_COLUMN_INDEX) {
final MyObject myObj = (MyObject) element;
final Image image = myObj .getImage();
Image newImage = null;
if(this.decorator != null) {
newImage = this.decorator.decorateImage(image, myObj );
}
return newImage == null ? image : newImage;
}
return null;
}
You can use DecoratingStyledCellLabelProvider which takes an IStyledLabelProvider and an ILabelDecorator as parameters:
new DecoratingStyledCellLabelProvider(styledLabelProvider,
PlatformUI.getWorkbench().getDecoratorManager()
.getLabelDecorator(), null);
I'm trying to create in-game window, using Table class. But when i added groups of images to that table, seems row() method has no influence to groups, they all are in the same place. Using Images instead of Groups works.
PS. I used Group to overlap images (kinda border for hover effect), don't know better way to do that.
Thanks
public class MyGroup extends Group{
public MyGroup(Image bg, Image thumb){
this.addActor(bg);
this.addActor(thumb);
}
}
public class ActionScreen extends Table {
MyGroup[] group =new MyGroup[8];
for (int i=0;i<8;i++){
group[i] = new MyGroup(new Image(skin.getDrawable("item-bg")),new Image(skin.getDrawable("item-bg-over")));
if (i==4){
row();
add(group[i]).top().padLeft(100);
}
else{
add(group[i]).top().padLeft(100);
}
}
Group's, by default, have zero size, so you have to manually set the size.
In your MyGroup constructor, you'd want to call something like this
this.setSize(bg.getWidth(), bg.getHeight());
I've got a JComboBox that potentially can have thousands of items. They're sorted, and there's find-as-you-type, so in principle it's not completely unusable.
In practice, it's pretty unusable with just a couple of hundred items. I managed to improve the initial display performance using setPrototypeDisplayValue(), but BasicListUI still insists on configuring the list cell renderer for every item in the box (see BasicListUI.updateLayoutState()).
This, or something like it, is apparently a known issue to Sun; it has been for going on eight years now, so I'm not holding my breath.
Short of implementing my own UI, has anyone got a workaround?
JList might be a better choice, as it uses a fly-weight approach to rendering and appears to support find-as-you-type.
If you use JComboBox, add entries to the model before the component itself starts listening. This SortedComboBoxModel uses a simple insertion sort that is acceptable for a few thousand entries:
class SortedComboBoxModel extends DefaultComboBoxModel {
/** Add elements by inserting in lexical order. */
#Override
public void addElement(Object element) {
this.insertElementAt(element, 0);
}
/** Insert in lexical order by name; ignore index. */
#Override
public void insertElementAt(Object element, int index) {
String name = element.toString();
for (index = 0; index < this.getSize(); index++) {
String s = getElementAt(index).toString();
if (s.compareTo(name) > 0) {
break;
}
}
super.insertElementAt(element, index);
}
}
Here's the hack that I came up with. The drawbacks are:
if you want to maintain the look and feel, you have to separately subclass each BasicComboBoxUI extension you care about
you have to use reflection to load your UI classes, since (for instance) a subclass of WindowsComboBoxUI won't load on Linux
it won't work with L&Fs (e.g. MacOS?) that don't extend BasicComboBoxUI
it makes assumptions about the ListCellRenderer that may not always be warranted
I'm still open to cleaner solutions.
class FastBasicComboBoxUI extends BasicComboBoxUI {
#Override
public void installUI(JComponent c) {
super.installUI(c);
Object prototypeValue = this.comboBox.getPrototypeDisplayValue();
if (prototypeValue != null) {
ListCellRenderer renderer = comboBox.getRenderer();
Component rendererComponent = renderer
.getListCellRendererComponent(this.listBox,
prototypeValue, 0, false, false);
if (rendererComponent instanceof JLabel) {
// Preferred size of the renderer itself is (-1,-1) at this point,
// so we need this hack
Dimension prototypeSize = new JLabel(((JLabel) rendererComponent)
.getText()).getPreferredSize();
this.listBox.setFixedCellHeight(prototypeSize.height);
this.listBox.setFixedCellWidth(prototypeSize.width);
}
}
}
}
I'm still open to cleaner solutions.
Later
Turns out this only solved some of the problems. Initial display of a combo box with a large number of items could still be really slow. I had to make sure the popup list box immediately gets a fixed cell size, by moving the code into the ComboPopup itself, as follows. Note that, as above, this depends on the prototype value.
#Override
protected ComboPopup createPopup() {
return new BasicComboPopup(comboBox) {
#Override
protected JList createList() {
JList list = super.createList();
Object prototypeValue = comboBox.getPrototypeDisplayValue();
if (prototypeValue != null) {
ListCellRenderer renderer = comboBox.getRenderer();
Component rendererComponent = renderer
.getListCellRendererComponent(list, prototypeValue, 0, false, false);
if (rendererComponent instanceof JLabel) {
// Preferred size of the renderer itself is (-1,-1) at this point,
// so we need this hack
Dimension prototypeSize = new JLabel(((JLabel) rendererComponent)
.getText()).getPreferredSize();
list.setFixedCellHeight(prototypeSize.height);
list.setFixedCellWidth(prototypeSize.width);
}
}
return list;
}
};
}