I'm learning JavaFX and working on a JavaFX application that will turn my laptop's touchscreen into a mini-piano. My prototype has a bunch of Buttons in place of piano keys, with each button mapped to a different Midi note. Clicking on a button with the mouse successfully triggers the button's onAction property and plays the associated note. Poking the button with my finger doesn't. The program clearly knows where my finger is because when I poke a button with my finger the button changes color, just as it does when I move the mouse pointer into it. I know that the problem is with JavaFX rather than with Java more generally or with my touchscreen because I wrote an essentially identical prototype in Swing where poking the screen succesfully plays a note. (I would gladly have stuck to Swing, too, if only Swing had any kind of multi-touch support. I want to play chords.) Is there something about JavaFX that I'm missing, such as a touchscreen event handler, or is something deeply wrong here?
For the record, I'm using OpenJDK 11.0.7 and OpenJFX 11.0.2 with a Xubuntu laptop. Here's the relevant bits of code.
#Override
public void start(Stage stage) {
stage.setTitle("Midi Test");
buttons = new Button[NOTE_VALUE.length];
for (int i = 0; i < NOTE_VALUE.length; i++) {
buttons[i] = new Button(NOTE_NAME[i]);
buttons[i].setPrefSize(KEY_WIDTH,KEY_HEIGHT);
buttons[i].setOnAction(this);
}
// Layout omitted for brevity
stage.show();
}
public void handle(ActionEvent event) {
// Identifies which button was pressed and plays the corresponding note
int index = -1;
for (int i = 0; i < buttons.length; i++) {
if (event.getSource().equals(buttons[i])) {
index = i;
break;
}
}
if (index != -1) {
channels[0].allNotesOff();
channels[0].noteOn(NOTE_VALUE[index],93);
}
}
After adopting #James_D's diagnostic suggestions (thanks, James) and doing some additional research, it looks like the problem is due to a known (but obscure) bug deep in the guts of OpenJFX 11. See the discussion here for details. There appear to be some workarounds, but the most straightforward solution would seem to be to try a more recent version of OpenJFX.
Related
I’ve trimmed down the code to only the relevant parts and posted it below. The code works fine. The video plays when you run it but it doesn’t have a seekbar.
public class Screen {
//JFrmae
private JFrame frame;
// Panel which I add the canvas to
private JPanel pVid = new JPanel();
// Canvas
Canvas canvas = new Canvas();
// Embedded Media Player
EmbeddedMediaPlayer emp;
/**
* Create the application.
*/
public Screen() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
//Frame
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
//Adding the panel to the frame
frame.getContentPane().add(pVid);
//Adding the canvas to the panel
pVid.add(canvas);
//Setting canvas size
canvas.setSize(715, 402);
//Loading the VLC native library
NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), "lib");
Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(), LibVlc.class);
//Initializing the media player
MediaPlayerFactory mpf = new MediaPlayerFactory();
//Misc
emp = mpf.newEmbeddedMediaPlayer(new Win32FullScreenStrategy(frame));
emp.setVideoSurface(mpf.newVideoSurface(canvas));
//Video file name and playing
String file = "video.mp4";
emp.prepareMedia(file);
emp.play();
//pack method
frame.pack();
}
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Screen window = new Screen();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
I’ve looked for an answer online for the last 4 days. Finally I decided to ask here. The official website for vlcj has pictures of a vlcj player they’ve made. There is a seekbar in those pictures. Link to the webpage which has the pics: http://capricasoftware.co.uk/#/projects/vlcj
They have a number of useful tutorials there but they don’t have any instructions for adding the seekbar.
Then I tried downloading their vlcj-player project from their GitHub page. It showed an error because it couldn’t resolve the “com.google.common.collect.ImmutableList” which is supposed to be imported. (At the moment I’m reading about ImmutableList and stuff and see if there’s a way to fix it.) Since I couldn’t figure that out yet, I looked for a class named seekbar or the like in their project. I couldn’t find any.
I also searched elsewhere online for the answer but I just couldn’t find it. I’d really appreciate any help. Thank you.
Edit:
(This edit is in response to the suggestion given to me by #caprica. Read their comment to this question and my reply to that in the comment to understand what I'm talking about here in this edit. I think it'll be useful for others in the future.)
All right, there must have been some problem with my Eclipse or computer. (I’ll type out how I fixed it at the end of this comment.) It’s working now. I’ll type out what I did step by step so that may be it’ll be useful to others in the future to download and install the project.
Download the project.
Import it as a Maven project. (Import > Maven > Existing Maven Project)
Now in Eclipse right click the imported project and select Run As > Maven Install
And that’s it. Now you can just run the project normally. If you don’t know how to run the project, do it like this. Right click the project and select Run As > Java Application and then Select VlcjPlayer – uk.co.caprica.vlcplayer.
Alternatively you can open the class where the main method is and run it. VlcjPlayer class is where the main method is located. The class is in the package uk.co.caprica.vlcplayer.
The problem I faced was that somehow all the necessary files didn’t get downloaded when I ran it as Maven Install. But it worked fine in another computer. Since I knew where the files are downloaded to, I just copied the folder from that PC and put it in the same place in my PC. The folder name is ‘repository’. It’s location is C:\Users\User Name\ .m2. Perhaps Eclipse in this PC has some problem. I’ll reinstall it later to avoid problems in the future.
And this may be useful, the VLC that’s installed in this PC is 64 bit. Not sure if that makes a difference but mentioning it just in case.
Now that the app is working fine I will see the code and see how the seekbar is made. Thanks a lot #caprica for telling me that I should import it as a Maven project. :)
The Basic Controls tutorial shows the essential approach: Add a panel of buttons to the frame and give each button an ActionListener that invokes the relevant media player command. As an example, this notional Rewind button would "skip backwards 10 seconds (-10,000 milliseconds)."
JPanel controlsPane = new JPanel();
JButton rewindButton = new JButton("Rewind");
rewindButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
mediaPlayerComponent.getMediaPlayer().skip(-10000);
}
});
controlsPane.add(rewindButton);
frame.add(controlsPane, BorderLayout.SOUTH);
The software design is up to you, but you should at least be aware of
JToolBar, seen here and here.
Action, seen here and cited here.
Timer, seen here as a way to repeat an Action.
All right, guys. I’ve figured out how to do it. I’m not sure how it was done in the official Vlcj project but I’ve figured out my own simple way by learning from the official project.
It just takes a few lines of code. It’s very simple.
These are the steps you have to follow:
Create a JSlider.
To the JSlider, add a mouseMotionListener (‘mouseDragged’ to be exact).
Inside that put in the code which would update the video position based on
the change in the JSlider.
Create a Timer.
Put the code inside it to set the value of the JSlider based on the position
of the video.
And that’s it!
This is the code. It comes inside the initialize() method which you can see in the code I’ve given in the question. (And of course you'll also have to create the JSlider and add it to the panel. I haven't shown the code since it's simple.)
js.addMouseMotionListener(new MouseMotionAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
if (js.getValue() / 100 < 1) {
emp.setPosition((float) js.getValue() / 100);
}
}
});
Timer timer = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
js.setValue(Math.round(emp.getPosition() * 100));
}
});
timer.start();
Some explanation.
The value you get when you use emp.getPosition always seems to be in decimals. It’s something like 0.1334344 at the start of the video and it’s something like 0.998988 at the end. But the value of JSlider is in int. From 0 to 100. So in the mouseMotionListener added to the JSlider I’ve converted the int value of the JSlider to float by dividing it by 100.
And in the action listener inside the timer I’ve multiplied the value of the video position by 100 and then rounded it off to make it an int value. So that value can be set in the JSlider to make it move in sync with the video.
I’m sure the code is rudimentary and there could be some best practices which I may not have followed. Sorry about that but I’m just getting into java by learning the stuff which I find interesting. Those who are good at java and have used such code in an actual project can comment below with how it can be improved.
I'm trying to develop a Mac OsX app provided by a system tray icon, so after the first attempt with the simplest code to achieve it I noticed that every apps tray icon's (both system and user apps) on mac osX (10.8) allows to activate the relative popup menu with both left and right click on it but with my project only the left (MouseEvent.BOTTON1) button causes the popup menu to pulldown. Here's my code:
public class SystemTrayDemo
{
private SystemTray tray;
private TrayIcon tray_icon;
public SystemTrayDemo()
{
if (!SystemTray.isSupported())
{
JOptionPane.showMessageDialog(null, "System tray not supported!");
return;
}
else
tray = SystemTray.getSystemTray();
final PopupMenu popup = new PopupMenu();
MenuItem exit = new MenuItem("Exit");
exit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if (tray != null)
{
tray.remove(tray_icon);
System.exit(0);
}
}
});
popup.add(exit);
//add tray icon
tray_icon = new TrayIcon(getIcon("images/wifi.png"), "Open documents...", popup);
tray_icon.setImageAutoSize(true);
try
{
tray.add(tray_icon); // adds icon
}
catch (AWTException ex) {}
}
private Image getIcon(String name)
{
URL _url = getClass().getResource(name);
return new ImageIcon(_url).getImage();
}
public static void main(String args[])
{
new SystemTrayDemo();
}
}
but how I already said, only through left mouse button click.
So during a further attempt I've tried to mimic the behavior of the tray icons of every other apps using a MouseListener and firing a left button event on right click event using dispatchEvent() method like so:
public static void fireMouseEvent(Component c)
{
MouseEvent me = new MouseEvent(c, // which
MouseEvent.MOUSE_CLICKED, // what
System.currentTimeMillis(), // when
MouseEvent.BUTTON1_MASK, // no modifiers
0, 0, // where: at (10, 10}
1, // only 1 click
true); // popup trigger
c.dispatchEvent(me);
}
the event will handled by the mouse listener but obviously TrayIcon Class is not a Component subclass and therefore the source of MouseEvent is null and I get a NPE. Here's my MouseListener:
class MouseAdapt extends java.awt.event.MouseAdapter
{
public void mouseClicked(java.awt.event.MouseEvent me)
{
int button = me.getButton();
if(button == java.awt.event.MouseEvent.BUTTON3)
{
fireMouseEvent(me.getComponent());
}
}
}
try
{
tray.add(tray_icon); // aggiungi l'icona
tray_icon.addMouseListener(new MouseAdapt());
}
catch (AWTException ex) {}
Sorry for my english, I hope that someone who have ever had some experience with that kind of projects can help me. I've searched for hours but with no luck. Thank You for your help.
Edit: There's now a library working to fix all of this here: https://github.com/dorkbox/SystemTray
to activate the [TrayIcon] relative popup menu with both left and right click
This is simply not possible on Mac + Java currently. Using reflection to invoke the underlying triggers doesn't seem to help. This is a bug.
https://bugs.openjdk.java.net/browse/JDK-8041890
only the left (MouseEvent.BOTTON1) button causes the popup menu to pulldown. Here's my code
Even this is broken in some Java versions (7u79), fixed with an upgrade...
https://bugs.openjdk.java.net/browse/JDK-7158615
Cross-Platform TrayIcon Support:
Albeit slightly off-topic, I wanted to add, some projects use a JXTrayIcon to accomplish some fancy drop-down menus in Linux/Windows, etc. These also cause problems on Mac despite a click-bug it already suffers from today as well as bugs with Gnome3 requiring a completely separate hack. But on Mac, any attempt to use the decorated menus causes the menu to linger and is a very bad experience for the end-user. The solution I settled on was to use AWT for Mac, Swing for everything else. The Java TrayIcon support is in dire need of a rewrite. JavaFX claims to help this initiative, but it's staged for Java 9. In the mean time, I'm sticking to OS-dependent hacks.
Related Tray Issues for Other Platforms
Furthermore, some Linux distributions like Ubuntu have removed the tray icon by default in the Unity desktop, causing further headaches. https://askubuntu.com/a/457212/412004
In addition, the transparency of the icon is replaced with a gray color on Gtk/Gnome or Qt/KDE powered desktops (Both OpenJDK and Oracle JRE suffer this)
https://stackoverflow.com/a/3882028/3196753
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6453521
In addition, Gnome3 powered desktops may show it in the wrong corner, not at all, or it may show but be unclickable (Both OpenJDK and Oracle JRE suffer this)
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=660157
https://bugzilla.redhat.com/show_bug.cgi?id=1014448
In addition to that, high-DPI screens on Windows have a bug that draws the icon incorrectly: Windows 8 Distorts my TrayIcon
So in summary, the state of the System Tray in Java is OK, but due to the combination of factors is quite fragmented and buggy in JDK6, JDK7 and JDK8.
I have a jFace wizard, I am using this to create a new project type eclipse plugin. As you can see from image below, I have one treeviewer on left side, and a SWT group on right side. What I want is when ever user selects one of the item from treeviewer, I should be able to create dynamic controls on right side SWT Group. Say user selects Test One, one right side I should be able to create few controls like label, text and few radio buttons on right side, similarly if user selects Test Two I should be able to create dynamic controls on right side.
Currently I tried below code:
tree.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
for (int i = 0; i < selection.length; i++) {
String tempStr = selection[i].toString();
tempStr = tempStr.replaceAll("TreeItem \\{", "");
String finalStr = tempStr.replaceAll("\\}", "");
if (finalStr.equals("Test One")) {
Button btn = new Button(g2, SWT.NONE); //g2 is right side group
btn.setText("Blaaaa");
btn.setVisible(true);
container.redraw();
}
}
But when I run, I see no changes on right group. Can anyone guide me what I am doing wrong? Any pointers would be very appreciated, since I am new to Eclipse development and SWT.
You probably didn't set a layout on the g2 group. This is the common cause for controls not showing up. You can also try using g2.layout() to ensure that the new controls are correctly laid out after you create them.
Additionally you could look at using a StackLayout so that once you create a set of controls you can just hide them all at once instead of destroying when the selection changes. This is often useful so that if the user comes back to a previous selection, they will find the data they entered in the same state when they switched the selection. Here is an example.
I am looking for a simple solution for the issue that my GWT DialogBox can be dragged out of the screen. The host has the CSS rule overflow:hidden because I do not want any scrollbars to appear.
Obviously I need to attach somehow a listener to the dragging and prevent moves that would bring it outside. I can only see onMouseMove, beginDragging, endDragging methods in DialogBox.
"We" have worked around this issue in the following way:
#Override
protected void endDragging(MouseUpEvent event)
{
int genericMargin = 60;
int leftMargin = -(this.getOffsetWidth() - genericMargin);
int lowerMargin = Window.getClientHeight() - genericMargin;
int rightMargin = Window.getClientWidth() - genericMargin;
int upperMargin = 0;
if (this.getAbsoluteLeft() > rightMargin)
{this.setPopupPosition(rightMargin, this.getPopupTop()); }
if (this.getAbsoluteLeft() < leftMargin)
{ this.setPopupPosition(leftMargin, this.getPopupTop()); }
if (this.getAbsoluteTop() > lowerMargin)
{ this.setPopupPosition(this.getPopupLeft(), lowerMargin);}
if (this.getAbsoluteTop() < upperMargin)
{ this.setPopupPosition(this.getPopupLeft(), upperMargin);}
super.endDragging(event);
}
BTW it correctly works as it is! ;)
I would suggest trying gwtquery-dnd. I have been using the drag and drop plugin and it works great. It has an option to setContianment(Element elem) which is what you are looking for. Some other features is that it has snap so you can snap to other widgets if you wish to dock your dialog box somewhere. It also has the ability to specify a handle similar to the DialogBox header for dragging.
http://code.google.com/p/gwtquery-plugins/wiki/DragAndDropPluginForGWTDeveloppers
You can investigate com.google.gwt.user.client.ui.DialogBox source code and override all methods for your need. There are a couple of methods responsible for dragging there.
Not sure you can solve this problem in other ways. Otherwise you need to develop custom draggable popup panel which I am sure not a good solution.
I have a strange issue: there is a SectionPart with composite, which is create from FormToolkit#createComposite(getSection()). Composite contains some number of widgets, which are positioned vertically one under other (as in a usual form). When the cursor is inside some widget, let's say input filed and I am clicking right between two fields on empty space, then focus automatically jumps to the first field in this composite.
I've tried to set SWT.NO_FOCUS style bit to the first widget in the form (usually it is a TableComboViewer) but it didn't helped (it seems, that this bit is not set on TableCombo, which is inside TableComboViewer).
So, have anybody faced something similar, or are there any workarounds for this problem or any clues what could it be?
Upd1: setting NO_FOCUS style helps for non TableComboViewer widgets (in this case they are not receiving focus). In case of TableComboViewer TableCombo widget contains Text widget, which receives focus, but even, if I add NO_FOCUS bit, it is not applied to Text style. I've checked source of TableCombo and there is a method checkStyle, which does following:
private static int checkStyle (int style) {
int mask = SWT.BORDER | SWT.READ_ONLY | SWT.FLAT | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
return SWT.NO_FOCUS | (style & mask);
}
I am not actually sure what it does, cause I am not really good in bitwise operation, but seems, that this is the problem, why I can't set NO_FOCUS flag.
I don't understand though, why when I am clicking on Composite, it tries to set foxus on it's children, can I somehow suppress this?
Upd2: The reason is probably found, it is said, that:
When the view is activated, focus is transferred to the form, which passes it to the first control capable of accepting focus, our link in this case.
And it seems, that it is not possible to forbid this.
Thanks in advance,
AlexG
You problem lies in Composite.setFocus().. have a look at this:
public boolean setFocus () {
checkWidget ();
Control [] children = _getChildren ();
for (int i= 0; i < children.length; i++) {
if (children [i].setFocus ()) return true;
}
return super.setFocus ();
}
As you can see, this will try to set the focus on the first control in the composite that will allow for the focus...
[EDIT - the following is added to clarify...]
The above method would not be a problem if it wasn't for the MouseListener that is installed on all Composites in FormToolkit.adapt(Composite composite):
public void adapt(Composite composite) {
composite.setBackground(colors.getBackground());
composite.addMouseListener(new MouseAdapter() {
public void mouseDown(MouseEvent e) {
((Control) e.widget).setFocus();
}
});
if (composite.getParent() != null)
composite.setMenu(composite.getParent().getMenu());
}
I have solved this problem on a number of occasions by having my own FormToolkit.adapt(Composite composite) in a sub-class that does the right thing - I just exchange setFocus() with forceFocus(). Though that can occasionally give you other problems...