I was under the impression that a touch screen emulated mouse events, however how would I handle multiple touch events?
I have tried adding a JPanel with a MouseMotionListener and outputting the values to the console. I however, am only getting values for the first touch on the screen.
I then tried splitting the screen down the middle, with a JPanel on either side, and a separate MouseMotionListener on each side, each one outputting to the console.
In this configuration, I still only see the values for the first finger on the screen.
Here is what I have so far:
JPanel jPaneL = new JPanel();
jPaneL.setName("Left");
jPaneL.addMouseMotionListener(mouseMotionL);
jPaneL.setBounds(0, 0, 960, 1280);
jPaneL.setBackground(Color.BLACK);
JPanel jPaneR = new JPanel();
jPaneR.setName("Right");
jPaneR.addMouseMotionListener(mouseMotionR);
jPaneR.setBounds(960, 0, 960, 1080);
jPaneR.setBackground(Color.RED);
jFrame.add(jPaneL);
jFrame.add(jPaneR);
And my MouseMotionListener, L and R are the exact same.
private static MouseMotionListener mouseMotionX = new MouseMotionListener() {
#Override
public void mouseDragged(MouseEvent e) {
String s = ((JPanel) e.getSource()).getName();
System.out.println(s);
}
#Override
public void mouseMoved(MouseEvent e) {
String s = ((JPanel) e.getSource()).getName();
System.out.println(s);
}
};
I have found libraries that support multi-touch, but I am looking to do this without using third-party libraries. How can I go about doing this using just native mouse listeners?
First I want to say that I would really recommend using JavaFX for such an application.
You can also integrate your JavaFX project in existing swing applications using JFXPanel.
However I have heard about MT4j which is a framework for multitouch in Java application which also supports Swing. I have not worked with it. So I can not tell you how good it works.
Related
I'm working on an on-screen keyboard for Windows and macOS and I've made a little test app. It has a single button and types the letter “M” to the active application. It works for Windows 10, but not Mac (I'm running macOS 10.12). In macOS, as soon as I press the button, whichever app I'm trying to send the "M" to loses focus (the cursor for text entry disappears), even though my single button "keyboard" has setFocusable(false) all over the place. I tried my own MouseListener on the button too.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class main {
private static Robot robot;
private static Rectangle rectangle;
public static void main(String[] args){
try {
robot = new Robot();
} catch (AWTException e) {
e.printStackTrace();
}
Button button = new Button("M");
button.setFocusable(false);
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(100, 100);
frame.add(button);
frame.setAlwaysOnTop(true);
//set everything I can think of to unfocusable!!!
frame.setFocusable(false);
frame.setAutoRequestFocus(false);
frame.setFocusableWindowState(false);
frame.getRootPane().setFocusable(false);
frame.setVisible(true);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
sendKeystroke();
}
});
//Instead of adding a listener to the button, I've also tried my own MouseListener.
/* button.addMouseListener(new MouseTrap());
rectangle = button.getBounds();*/
}
private static void sendKeystroke(){
robot.keyPress(KeyEvent.VK_M);
robot.keyRelease(KeyEvent.VK_M);
}
private static class MouseTrap extends MouseAdapter{
#Override
public void mouseClicked(MouseEvent e) {
if (rectangle.contains(e.getPoint())){
sendKeystroke();
}
}
}
}
It seems like macOS does let some apps have focus without taking the cursor from another. e.g. VMware or spotlight search from the system tray.
Cursor for VMware and IntelliJ at the same time
I've seen other answer which are non-Java:
Virtual Keyboard Cocoa & Objective C
But do I really have to go all native when Java works on Windows? Apart from the learning curve (not done anything native on a Mac), I want to keep Win and Mac versions versions as close as possible.
Anyone know how I could get this working using straight Java?
(Note: As was the case with the questioner for the above link, I can't just use a keyboardview, as I want send modified/additional data from the keyboard e.g. text predictions. I believe that would require additional native code again.)
I have tried to find the way very much. But it seems that it is not possible by pure Java without any native code.
I program a simple RTS game now, and it is my first experience in game design. My problem is that when I use createBufferStrategy(2) all swing elements (buttons etc...) not displayed after bufferStrategy.show(); method is invoked. My game is full of buttons, tables and other crap, and I really don't want to code all this by my own. Also I really like Java's layouts, and want to make all GUI on this.
So, here is little code example, not from my game, but it is a good demonstration of my problem. Thanks.
Btw, I understand the source of my problem. I know that swing draw mechanic is event-based, while using bufferstrategy is not event-based. But I don't know how to solve this. Thank you.
And final - I don't want to use default swing event-based approach becouse it is slow for games, and as far as I know the bufferstratgey is only approach for games. Thx.
public static void main(String[] args){
final JFrame frame = new JFrame();
JPanel menuPanel = new JPanel();
final Button button = new Button("Exit");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
menuPanel.add(button);
frame.add(menuPanel);
frame.setPreferredSize(new DimensionUIResource(800, 600));
//frame.setResizable(false);
//frame.setUndecorated(true);
//frame.setIgnoreRepaint(true);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final long delay = 1000/60;
frame.pack();
frame.setVisible(true);
final GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
if (device.isFullScreenSupported()){
device.setFullScreenWindow(frame);
// this place. If I turn into fullscreen mode button disappear. And if I stay in windowed mode button exist and work;
}
frame.createBufferStrategy(2);
final BufferStrategy bufferStrategy = frame.getBufferStrategy();
Thread renderingThread = new Thread(){
public void run(){
while (true){
long startRenderingTime = System.currentTimeMillis();
Graphics g = bufferStrategy.getDrawGraphics();
g.setColor(Color.white);
g.fillRect(0,0,1680,1050);
//button.paint(g);
//button.paintAll(g);
// I don't know how to draw button!
g.dispose();
if (!bufferStrategy.contentsLost()){
bufferStrategy.show();
}
long endRenderingTime = System.currentTimeMillis();
long actionTime = endRenderingTime-startRenderingTime;
try {
if (actionTime>delay){
sleep(5);
} else {
sleep(delay-actionTime);
}
} catch (InterruptedException e){
return;
}
}
}
};
renderingThread.start();
}
});
}
You're running an infinite loop on Swings EDT, effectively blocking Swing from doing anything.
I don't see for what you even need BufferStrategy when you want to display Swing elements. To combine custom rendering with Swing components you normally just create a component that renders your stuff and add it to the normal layout.
Your component just overwrites paintComponent() and draws whatever it needs to. You can easily trigger an update of your component by calling repaint() on it. This performs usually well enough. Note that Swing components are double buffered by default, so there is no need to work with BufferStrategy there.
If you want to stick to active rendering, you could call Swings rendering chain selectively, for example you could get the Frame's ContentPane and just call paint() in your rendering loop. But hacking it this way may cause unwanted side effects.
public class Gui extends JFrame{
JTextField tf_input;
JTextArea ta_output;
JScrollPane sp_taop;
private class klis implements KeyListener{
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
if (e.getKeyCode()==KeyEvent.VK_ENTER){
//System.out.println("enter"); //debug
if (!tf_input.getText().isEmpty()){
String input = tf_input.getText();
ta_output.setText(ta_output.getText()+input+'\n');
System.out.println(input); //debug
System.out.println("ok!"); //debug
sp_taop.validate();
tf_input.setText(null);
}
}
}
}
Gui(){
System.out.println("hello");
inti();
render();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void inti() {
setSize(800, 600);
//text field input
tf_input = new JTextField();
tf_input.setSize(550, 24);
tf_input.addKeyListener(new klis());
//text Area
ta_output = new JTextArea("hello World\n",30,60);
ta_output.setSize(ta_output.getPreferredSize());
ta_output.setLineWrap(true);
ta_output.setEditable(false);
sp_taop = new JScrollPane();
sp_taop.add(ta_output);
sp_taop.setSize(ta_output.getSize().width+20,ta_output.getSize().height);
sp_taop.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
}
private void render() {
Panel p = new Panel(null);
ta_output.setLocation(0, 0);
sp_taop.setLocation(10, 10);
tf_input.setLocation(10, (sp_taop.getSize().height+20));
ta_output.repaint();
//adding
p.add(sp_taop);
p.add(tf_input);
add(p);
}
}
I'm running this on java 1.7.0_25 on vbox 4.3.4 lUbuntu
The problem is that the jscroll is not updating itself! What should i do?
I've been searching google for hours now and i have not found anything close to what I am looking for.
By the way sorry about the plain code it was hard to explain the problem without it.
Don't use JScrollPane#add, this is not how scroll panes work, instead try using JScrollPane#setViewportView
Take a look at How to use Scroll Panes
Don't add you text field to another container. Components can only have a single parent, so adding it to a second container will remove it from the first.
On a side note. I would avoid the use of KeyListener, text components have the capacity to consume key events, meaning that your listener may not actually be notified. Also, if it is called, the component will be in the middle of of mutation operation (it will be trying to update it's model) which can cause unexpected issues and possibly dirty updates.
I might be tempted to use a DocumentListener in this case, but you would need to test it.
I would also avoid the use of null layouts. To start with, you won't be able to effect the position of the text field within the context of the scroll pane as the scroll pane uses it's own layout manager.
Moreover, the differences between OS, video drivers and fonts makes the potential rendering outputs endless. Layout managers take out the guess work when dealing with these situations
I'm creating a small crypto app for the desktop using java.
I'm using JFrames (import javax.swing.JFrame) with Oracle
JDeveloper 11g under Linux.
I want to have a "welcome" form/frame where users can choose
their encryption method, and then on choosing the method,
I want to dynamically create the appropriate form for the
chosen encryption method and also destroy/free/dispose() of
the welcome form. When the user has finished their encrypting,
they should close the frame/form (either by clicking on the
x at the top right - or using the Exit button or by any
method) and the welcome frame should be dynamically recreated
and appear.
I've tried various things - btnEncode_actionPerformed(ActionEvent e)
then this.dispose() - and I've fiddled with this_windowClosed(WindowEvent e)
and dispose(), but nothing seems to work.
Even a workaround using setVisibl(true/false) would be acceptable at
this stage - this has been wrecking my head all day. It's very
easy to do in Delphi!
TIA and rgs,
Paul...
something like this usually does the trick: (Note I haven't tested this)
public class WelcomeMsg extends JFrame
.
.
.
public void btnContinue_actionPerformed(ActionEvent e)
{
this.dispose();
SwingUtilities.invokeLater(new Runnable(){ new JFrameAppropriateWindow(args) });
}
where btnContinue is the Continue button on your welcome form and JFrameAppropriateWindow is the next frame you would like to show depending on the user's choice. Args are any arguments you need to pass.
When you are ready, you can simply dispose the current frame and relaunch an instance of WelcomeMsg
I put together this simple example for creating and displaying a panel depending on a user choice.
public class Window extends JFrame {
public Window() {
this.setLayout(new BorderLayout());
JComboBox encryptionCombobox = new JComboBox();
encryptionCombobox.addItem("foo");
encryptionCombobox.addItem("bar");
//...
encryptionCombobox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// find choices and the correct panel
JPanel formPanel = new JPanel();
formPanel.setOpaque(true);
formPanel.setBackground(Color.RED);
//...
Window.this.add(formPanel, BorderLayout.CENTER);
Window.this.validate();
Window.this.repaint();
}
});
add(encryptionCombobox, BorderLayout.NORTH);
}
public static void main(String[] args) {
new Window().setVisible(true);
}
}
When I come to think about it, you should probably use a CardLayout instead, which allows you to switch between different panels (cards).
I am building a Java Swing application that needs to support both an embedded browser and ActiveX. The easy way to do this seemed to be to use JDICplus, which just embeds IE in your application. That would have covered both requirements.
I also need to overlay some buttons on top of this browser view so the user can navigate between views. To do that, I have a JLayeredPane to which I add views, and at a higher layer, buttons. This works in my pure Java views. However, on my Internet view, the Internet draws on top of the buttons. In other words, it doesn't seem to respect the JLayeredPane. I'm guessing this is because it is a native component and not a Java component.
To be sure, I put the Internet pane into a JInternalFrame, and the buttons in the other, and put both of the internal frames into a JDesktopPane. When I drag the button frame on top of the Internet frame, the Internet frame jumps to the foreground and covers the other frame. It's as if the embedded IE steals the focus and puts itself in the forefront of my other windows.
My question is this: is there any way to draw Java components on top of these Windows/IE components reliably? Or, am I not going to get anywhere mixing Java with IE? Are there other options to meeting my requirement of an embedded browser and ActiveX support (which technically, could be a different view--in other words, I could have an Internet view and another view that just supports ActiveX). I'm open to suggestions. I have looked at other free browser components for Java, and as everyone will tell you, it's discouraging.
Check out Sun's article on mixing heavy and light components - since JDICPlus basically embeds IE into your app, it's a heavyweight component.
You may be able to place buttons over the browser window by using other heavyweight components (i.e. AWT Button), or do something like place the button into a JPopupMenu placed over the browser with setDefaultLightWeightPopupEnabled(false) set on it to make it heavyweight.
Edited
I wrote an example using JPopupMenu to display a JButton over a heavyweight component - JPopupMenu works, but it does have built in behavior to close the menu when the popup or components in the popup lose focus. I added a MouseMotionListener to the heavyweight component to show the popups when the mouse entered a bounding box near where the buttons should be. Not sure if this works for you as the buttons aren't always shown.
Including a code example and screenshot -
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
public class LightHeavy extends JFrame {
private Component heavyweightComponent;
private JPopupMenu backButton, forwardButton;
public LightHeavy() {
super("LightHeavy");
heavyweightComponent = buildHeavyweightComponent();
heavyweightComponent.setBackground(Color.ORANGE);
heavyweightComponent.setSize(640, 480);
getContentPane().add(heavyweightComponent, BorderLayout.CENTER);
ImageIcon backArrow = new ImageIcon("left_arrow_128.png");
backButton = buildPopup(backArrow);
ImageIcon forwardArrow = new ImageIcon("right_arrow_128.png");
forwardButton = buildPopup(forwardArrow);
heavyweightComponent.addMouseMotionListener(new MouseInputAdapter() {
public void mouseMoved(MouseEvent e) {
Rectangle backHotSpot = new Rectangle(0, 0, 200, 200);
Rectangle forwardHotSpot = new Rectangle(heavyweightComponent.getWidth() - 200, 0, 200, 200);
if (backHotSpot.contains(e.getPoint())) {
backButton.show(heavyweightComponent, 0, 0);
} else if (forwardHotSpot.contains(e.getPoint())) {
forwardButton.show(heavyweightComponent,
heavyweightComponent.getWidth() - forwardButton.getWidth(), 0);
}
}
});
}
private Component buildHeavyweightComponent() {
return new Canvas() {
public void paint(Graphics og) {
super.paint(og);
Graphics2D g = (Graphics2D)og;
String big = "Heavyweight Component";
g.setFont(getFont().deriveFont(20F));
Rectangle2D bigBounds = g.getFontMetrics().getStringBounds(big, g);
g.drawString(big,
(this.getWidth() - (int)bigBounds.getWidth()) / 2,
(this.getHeight() - (int)bigBounds.getHeight()) / 2);
String little = "(assume this is JDICplus)";
g.setFont(getFont().deriveFont(10F));
Rectangle2D littleBounds = g.getFontMetrics().getStringBounds(little, g);
g.drawString(little,
(this.getWidth() - (int)littleBounds.getWidth()) / 2,
(this.getHeight() + (int)littleBounds.getHeight()) / 2);
}
};
}
private JPopupMenu buildPopup(Icon icon) {
JButton button = new JButton(icon);
JPopupMenu popup = new JPopupMenu();
popup.add(button);
popup.setBorderPainted(false);
popup.setLightWeightPopupEnabled(false);
return popup;
}
public static void main(String[] args) {
JFrame f = new LightHeavy();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
Here's a screenshot with the JButton on the left showing - note that you also won't be able to do any cool transparency effects, as you're dealing with heavyweight components.