How can I associate custom widgets with TreeItems in SWT? - java

I have created a custom widget--an SWT Group that consists of several buttons, labels, images and perhaps several other widgets I might need to add in the future. I would like to make this custom widget a tree item, so that I can get the indentation and the expand/collapse functionality of a tree.
Here is an image that shows what I am trying to achieve:
I created this example with the Google Web Toolkit and I'd like to implement it with SWT.
The SWT TreeItem has methods to set the text and the image, but I could not find a way to make the tree item be a custom widget. If it is not possible to associate custom widgets with SWT tree items, suggestions about other ways to organize custom widgets in a tree with indentation and expand/collapse functionality would be very helpful too. Thanks!

The PGroup widget from the Eclipse Nebula project does the job. It lets you enclose SWT Composites and supports collapsing and expanding. Indentation can be achieved by using layouts (e.g., GridLayout) for the contents of the PGroup and layout data (e.g., GridData) to specify the indentation of a component inside the PGroup.
The ExpandBar (which is a standard SWT widget) also seems like a possible solution, but I have not experimented with it.

It seems to be possible to use an event SWT.PaintItem to add custom drawing:
https://www.eclipse.org/articles/Article-CustomDrawingTableAndTreeItems/customDraw.htm
Source:
Embed custom widget in SWT Tree or Table
1 Display display = new Display();
2 Shell shell = new Shell(display);
3 shell.setBounds(10, 10, 350, 200);
4 Image xImage = new Image (display, 16, 16);
5 GC gc = new GC(xImage);
6 gc.setForeground(display.getSystemColor(SWT.COLOR_RED));
7 gc.drawLine(1, 1, 14, 14);
8 gc.drawLine(1, 14, 14, 1);
9 gc.drawOval(2, 2, 11, 11);
10 gc.dispose();
11 final int IMAGE_MARGIN = 2;
12 final Tree tree = new Tree(shell, SWT.CHECK);
13 tree.setBounds(10, 10, 300, 150);
14 TreeItem item = new TreeItem(tree, SWT.NONE);
15 item.setText("root item");
16 for (int i = 0; i < 4; i++) {
17 TreeItem newItem = new TreeItem(item, SWT.NONE);
18 newItem.setText("descendent " + i);
19 if (i % 2 == 0) newItem.setData(xImage);
20 item.setExpanded(true);
21 item = newItem;
22 }
23 tree.addListener(SWT.MeasureItem, new Listener() {
24 public void handleEvent(Event event) {
25 TreeItem item = (TreeItem)event.item;
26 Image trailingImage = (Image)item.getData();
27 if (trailingImage != null) {
28 event.width += trailingImage.getBounds().width + IMAGE_MARGIN;
29 }
30 }
31 });
32 tree.addListener(SWT.PaintItem, new Listener() {
33 public void handleEvent(Event event) {
34 TreeItem item = (TreeItem)event.item;
35 Image trailingImage = (Image)item.getData();
36 if (trailingImage != null) {
37 int x = event.x + event.width + IMAGE_MARGIN;
38 int itemHeight = tree.getItemHeight();
39 int imageHeight = trailingImage.getBounds().height;
40 int y = event.y + (itemHeight - imageHeight) / 2;
41 event.gc.drawImage(trailingImage, x, y);
42 }
43 }
44 });
45 shell.open();
46 while (!shell.isDisposed()) {
47 if (!display.readAndDispatch()) display.sleep();
48 }
49 xImage.dispose();
50 display.dispose();

Related

Make a button with an image

In fact, I've managed to do that BUT i get a problem that can be easily seen in the following image:
As you can see, there's a border between the image "jugar" and the final of the button. All I want to do is to remove that, so only the background image and the button "jugar" are seen. Here's my code:
public final class GUI extends Application {
#Override
public void start(final Stage primaryStage) throws InterruptedException, FileNotFoundException {
primaryStage.setTitle("CARCASSONE");
StackPane layout = new StackPane();
ImageView jugar = new ImageView(new Image(new FileInputStream("JUGAR.png")));
final Button openButton = new Button(null, jugar);
openButton.;
layout.getChildren().add(openButton);
BackgroundImage bI = new BackgroundImage(new Image(new FileInputStream("CARCASSONE.png")), null, null, null, null);
layout.setBackground(new Background(bI));
openButton.setOnAction(
new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
jugarPartida(primaryStage);
}
});
Scene inici = new Scene(layout, 610, 900);
primaryStage.setScene(inici);
primaryStage.show();
}
I must use JavaFX, so jbutton can't be used.
Any idea to solve that? Just want to remove that annoying border.
The problem with a transparent background is that there’s still an invisible rectangular area that responds to mouse clicks.
You can set the button’s region shape and its clip to a shape that matches your image bounds, so the Button effectively does not exist outside of those bounds:
openButton.setStyle("-fx-padding: 0;");
SVGPath shape = new SVGPath();
shape.setContent("M 18 0 "
+ "H 251 C 265 0 277 7 277 25 "
+ "V 52 C 277 69 265 76 251 76 "
+ "H 18 C 12 76 0 69 0 52 "
+ "V 25 C 0 7 12 0 18 0 "
+ "z");
shape.setFill(Color.BLACK);
openButton.setShape(shape);
openButton.setClip(shape);
Quick SVG path tutorial:
M means moveto (start drawing at that position)
H means draw horizontal line to the specified X position
V means draw vertical line to the specified Y position
C means curveto (draw Bézier curve using specified control points; last coordinate pair is the curve’s final endpoint)
z means close the shape
What you can do is apply css to set the color of openbutton to something like rgba(255, 255, 255, 0.00). You can also do this directly in code.
Something like String style = "-fx-background-color: rgba(255, 255, 255, 0.00);";
openButton.setStyle(style);
The last 0.0 is will make it transparent.

BarChart Labels in primefaces not showing

I am working at a project that requires a BarChart at the index page.
I want it to display underneath the bars, the labels set in the chart series, but it only will display the value set in the first chart series added to the chart model.
Here is my code:
vencidoMas90dias = new BarChartSeries();
vencido90dias = new BarChartSeries();
vencido60dias = new BarChartSeries();
vencido30dias = new BarChartSeries();
vence30dias = new BarChartSeries();
vence60dias = new BarChartSeries();
vence90dias = new BarChartSeries();
vencidoMas90dias.set(">90 días", v.getVencidoMasTresMeses());
vencido90dias.set("90 y 60 días", v.getVencidoTresMeses());
vencido60dias.set("60 y 30 días", v.getVencidoDosMeses());
vencido30dias.set("30 y 1 día", v.getVencidoMes());
vence30dias.set("1 a 30 días", v.getTreintaDias());
vence60dias.set("30 a 60 días", v.getSesentaDias());
vence90dias.set("60 a 90 días", v.getNoventaDias());
modelo.addSeries(vencidoMas90dias);
modelo.addSeries(vencido90dias);
modelo.addSeries(vencido60dias);
modelo.addSeries(vencido30dias);
modelo.addSeries(vence30dias);
modelo.addSeries(vence60dias);
modelo.addSeries(vence90dias);
But the chart is displaying only one label in the center bar, and I need to display the label for each bar.
Does anybody know what is wrong with this? I am using Primefaces 4.0, and the examples in the showcase seem to have some differences, and they are not very clear sometimes.
Thanks in advance
You want to draw BarChart, why add BarChartSeries? I think you could setup BarChart with the following code:
CartesianChart modelo = new CartesianChart();
modelo.setLabel("Label");
ChartSeries s = ChartSeries();
s.set(">90 días", v.getVencidoMasTresMeses());
s.set("90 y 60 días", v.getVencidoTresMeses());
s.set("60 y 30 días", v.getVencidoDosMeses());
s.set("30 y 1 día", v.getVencidoMes());
s.set("1 a 30 días", v.getTreintaDias());
s.set("30 a 60 días", v.getSesentaDias());
s.set("60 a 90 días", v.getNoventaDias());
modelo.add(s);
modelo.setTitle("Title");

Set ScrollableComposite position to location

Using the SWT ScrollableComposite, is there an easy way in which to set the scrollbar position to jump in such a way that a particular element will be positioned at the top?
For example, if I had such a composite filled with 26 labels going down with the letters of the alphabet in order:
...then, say that I want to set my view to the "J" label and have the scrollbar position set like this:
(This is only example - if I really wanted to do what I am describing here, I would clearly just use a listbox or a table for my letters instead.)
This is similar to how Internet Browsers work when jumping to a specific tag within a page.
This can likely be done with a bunch of manual measurement calculations, if necessary, but my hope is that something simpler exists.
I believe you are looking for below method on ScrolledComposite
org.eclipse.swt.custom.ScrolledComposite.showControl(Control) //make it visible in view port
org.eclipse.swt.custom.ScrolledComposite.setOrigin(Point) //sets left corner coordinates, read SWT docs
Updated Answer:
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
Map<String,Control> controlMap = new HashMap<String,Control>();
final ScrolledComposite scrollComposite = new ScrolledComposite(shell,
SWT.V_SCROLL | SWT.BORDER);
final Composite parent = new Composite(scrollComposite, SWT.NONE);
for (int i = 0; i <= 50; i++) {
Label label = new Label(parent, SWT.NONE);
String index = String.valueOf(i);
controlMap.put(index, label);
label.setText(index);
}
GridLayoutFactory.fillDefaults().numColumns(1).applyTo(parent);
scrollComposite.setContent(parent);
scrollComposite.setExpandVertical(true);
scrollComposite.setExpandHorizontal(true);
scrollComposite.addControlListener(new ControlAdapter() {
public void controlResized(ControlEvent e) {
Rectangle r = scrollComposite.getClientArea();
scrollComposite.setMinSize(parent.computeSize(r.width,
SWT.DEFAULT));
}
});
shell.open();
Control showCntrl = controlMap.get(String.valueOf(5));
if(showCntrl != null){
scrollComposite.setOrigin(showCntrl.getLocation());
}
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}

generating swt shell at the center of its parent shell

I have SWT wizard page as my parent shell , for creating another shell on click of button i am writing following code
Shell permissionSetShell = new Shell(Display.getCurrent().getActiveShell(), SWT.CENTER|SWT.DIALOG_TRIM|SWT.APPLICATION_MODAL);
permissionSetShell.setText(PropertyClass.getPropertyLabel(QTLConstants.PERMISSION_SET_COLUMN_LABEL));
// Add shell to the center of parent wizard
permissionSetShell.setLayout(componentsRenderer.createGridLayout(1, false, 0, 5, 0, 0));
Monitor primary = Display.getCurrent().getPrimaryMonitor ();
Rectangle bounds = primary.getBounds ();
Rectangle rect = Display.getCurrent().getActiveShell().getBounds ();
int x = bounds.x + (bounds.width - rect.width) / 2;
int y = bounds.y + (bounds.height - rect.height)/2;
permissionSetShell.setLocation (x, y);
but as the child shell means this shell is not placed at the center of SWT wizard that is parent shell why?
Rectangle screenSize = display.getPrimaryMonitor().getBounds();
shell.setLocation((screenSize.width - shell.getBounds().width) / 2, (screenSize.height - shell.getBounds().height) / 2);
If you are writing a dialog or a child component you may want to use getParent instead of asking the display for the primary monitor so that the window is centered on the current screen for multiple monitor setups.
Rectangle parentSize = getParent().getBounds();
Rectangle shellSize = shell.getBounds();
int locationX = (parentSize.width - shellSize.width)/2+parentSize.x;
int locationY = (parentSize.height - shellSize.height)/2+parentSize.y;
shell.setLocation(new Point(locationX, locationY));
I think the best would be to use style SWT.SHEET for such dialog.
I just ran into this same problem. The solution I got is a little different. This might help others with the same issue. The context is a shell (hoverShell) that hovers over the parent (shell) for a couple of seconds displaying a message.
private void displayMessage(Shell shell, String message) {
Shell hoverShell = new Shell(shell, SWT.ON_TOP);
hoverShell.setLayout(new FillLayout());
Label messageLabel = new Label(hoverShell, SWT.NONE);
messageLabel.setText(message);
Point shellLocation = shell.getLocation();
hoverShell.pack();
hoverShell.setLocation(shellLocation.x + (shell.getSize().x / 2) - (hoverShell.getSize().x / 2), shellLocation.y + 40);
hoverShell.open();
Display.getDefault().timerExec(2000, new Runnable() {
#Override
public void run() {
hoverShell.dispose();
}
});
}
In a nutshell this is the following formula:
child_location.x = parent_location.x + .5*(parent_width.x) - .5*(child_width.x)
If you want y then it's the exact same I believe. May depend if the top border of the window is calculated.
tried, tested and working code:
int width = display.getClientArea().width;
int height = display.getClientArea().height;
shell.setLocation(((width - shell.getSize().x) / 2) + display.getClientArea().x, ((height - shell.getSize().y) / 2) + display.getClientArea().y);

How to display frame only when required & set frame to appear on top all the time?

My program will alert users when data (stock name & price) in the database matches with the data (stock name and price) from Yahoo Finance. With the help of HarryJoy i'm able to implement a pop up notification.
Problem is the pop up location on the screen is based on the database loop (int db). The frame will pop even if data doesn't match.
How can I set a counter or some method to pop up the frame only when database data = Yahoo Finance data? Also, my notification panels appears to be behind the main frame. How can make the panels appear on top of my main frame?
I hope I've given enough information, please ask if still unclear. Any guidance will be appreciated! Thanks!
In the database (using code sample only to display my explanation in order, source code below).
Object 1 = match
Object 2 = doesn't match (hence there's a gap)
Object 3 = match
Object 4 = match
Screenshot:
Code:
for (int db=0; db<= rowCount; db++)
{
Object popSymbol = table.getModel().getValueAt(db, 0);
String popupSymbol = popSymbol.toString();
Object popValue = table.getModel().getValueAt(db, 1);
String str = popValue.toString();
double popStockValue = Double.valueOf(str).doubleValue();
String stockNameDB = popupSymbol;
StockPara stock = YahooStock.getInstance().getStockPrice(stockNameDB);
double stockPriceDB = Math.round(stock.getPrice());
final JFrame popUpFrame;
final JPanel popupPanel;
if (stockPriceDB == popStockValue)
{
String header = "Stock: " + stock.getTicker() + " is now # " + stock.getPrice();
String message = "";
popUpFrame = new JFrame();
popUpFrame.setSize(320,90);
popUpFrame.setUndecorated(true);
popUpFrame.getContentPane().setLayout(null);
popupPanel = new JPanel();
popupPanel.setBorder(new LineBorder(new Color(0, 0, 0)));
popupPanel.setBounds(0, 0, 320, 90);
getContentPane().add(popupPanel);
popupPanel.setBackground(new Color(255, 255, 224));
popupPanel.setLayout(null);
popUpFrame.add(popupPanel);
// Other labels, images, etc.
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Insets toolHeight = Toolkit.getDefaultToolkit().getScreenInsets(popUpFrame.getGraphicsConfiguration());
popUpFrame.setLocation(screenSize.width - popUpFrame.getWidth(), screenSize.height - toolHeight.bottom - (popUpFrame.getHeight() * (db+1)));
}
}
To solve your issue quickly, simply create an additional counter (int counter = 0;). Then use that counter instead of db to position your popUpFrame and right after that increment counter.
int counter = 0; // Initiate outside de loop
...
for(int db=0; db<= rowCount; db++) {
...
if (stockPriceDB == popStockValue) {
...
popUpFrame.setLocation(screenSize.width - popUpFrame.getWidth(),
screenSize.height - toolHeight.bottom - (popUpFrame.getHeight() * (counter+1)));
counter++;
}
}
To bring your frame to the front use:
popUpFrame.toFront()
and to force it to be always on top (although I would really not recommend that because it is more annoying for the user than anything else):
popUpFrame.setAlwaysOnTop(true);
This is not necessarily supported by all platforms.
for on top issue, use
notificationPanel.requestFocus();

Categories