OpenGL and AWT/Swing User Interface - java

I am currently developing 3d viewer with OpenGL (LWJGL) for an embedded system.
Without going into much detail, there is an application written on Java/Swing that currently has fully implemented UI and logic on Java+Swing. But it was decided that instead of 2d top-down picture it'd be cool to have 3d view as well, and that's where I come in.
I will say that I have to use GLES 3.0 or Opengl 2.1, and I prefer GLES because it has more features compared to 2.1
I also have a standalone application implemented with GLFW windowing system (a default for LWJGL) that runs fine on the device - it doesn't lag and gives decent FPS. Again, when running in a GLFW window.
But now I need to attach it to JFrame preferably, and that's where my problems start. Basically, what I need is to have my 3D view render as a background, and then have Swing buttons/panels and additional windows (for example with options menu) display on top of it.
I've implemented a basic algorhythm of simply reading the FrameBuffer and drawing it on a canvas as a raster image. But that's SLOW. I get like 10 FPS with that.
private void render()
{
logic.Render(window); //GLFW window
window.update();
ByteBuffer nativeBuffer = BufferUtils.createByteBuffer(GlobalSettings.WINDOW_WIDTH*GlobalSettings.WINDOW_HEIGHT*4);
BufferedImage image = new BufferedImage(GlobalSettings.WINDOW_WIDTH,GlobalSettings.WINDOW_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR);
GLES30.glReadPixels(0, 0, GlobalSettings.WINDOW_WIDTH,GlobalSettings.WINDOW_HEIGHT, GLES20.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, nativeBuffer);
byte[] imgData = ((DataBufferByte)image.getRaster().getDataBuffer()).getData();
nativeBuffer.get(imgData);
Graphics g = canvas.getGraphics();
g.drawImage(image, 0,0, GlobalSettings.WINDOW_WIDTH,GlobalSettings.WINDOW_HEIGHT, null);
}
The other thing I've tried is using this library https://github.com/LWJGLX/lwjgl3-awt that seems to be recommended a lot. The problem is, it uses some OpenGL 3.1 functionality, and getting it to work AT ALL under 2.1 context was a huge chore. But as for GLES - I couldn't make it work at all, and I obviously can't have it create context for 2.1 and then use GLES functionality further on, so it basically breaks my entire rendering code.
Maybe I'm just not doing it right, but anyway - I couldn't make it work for me.
And that's pretty much where I stand. I thought I'd ask for help here. To me, at this point, it seems likely that I'll have to write the entire interface for OpenGL/GLFW entirely, and forgo Swing completely. Which is not ideal at all - I even wonder if we have such time at all.
Please, point me in the right direction if there are ways to make my thing work with AWT.

I will post an answer myself. It works well both on Linux desktop and on the embedded system, with good performance so far as I can see.
The idea is taking an EGL context and GLES, and setting AWT canvas surface as a direct target for the context. You don't need to read buffer and then paint it on the canvas.
Below is my Window class initialization.
private Canvas canvas;
private JAWTDrawingSurface ds;
public long display;
private long eglDisplay;
public long drawable;
private long surface;
public static final JAWT awt;
static {
awt = JAWT.calloc();
awt.version(JAWT_VERSION_1_4);
if (!JAWT_GetAWT(awt))
throw new AssertionError("GetAWT failed");
}
public void lock() throws AWTException {
int lock = JAWT_DrawingSurface_Lock(ds, ds.Lock());
if ((lock & JAWT_LOCK_ERROR) != 0)
throw new AWTException("JAWT_DrawingSurface_Lock() failed");
}
public void unlock() throws AWTException {
JAWT_DrawingSurface_Unlock(ds, ds.Unlock());
}
public void Init2()
{
frame = new JFrame("AWT test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.setPreferredSize(new Dimension(width, height));
canvas = new Canvas();
frame.add(canvas);
frame.pack();
frame.setVisible(true);
frame.transferFocus();
int error;
System.out.println("Window init2() started");
this.ds = JAWT_GetDrawingSurface(canvas, awt.GetDrawingSurface());
//JAWTDrawingSurface ds = JAWT_GetDrawingSurface(canvas, awt.GetDrawingSurface());
try
{
lock();
try
{
JAWTDrawingSurfaceInfo dsi = JAWT_DrawingSurface_GetDrawingSurfaceInfo(ds, ds.GetDrawingSurfaceInfo());
JAWTX11DrawingSurfaceInfo dsiWin = JAWTX11DrawingSurfaceInfo.create(dsi.platformInfo());
int depth = dsiWin.depth();
this.display = dsiWin.display();
this.drawable = dsiWin.drawable();
System.out.printf("EGL Display %d, drawable: \n", display, drawable);
eglDisplay = eglGetDisplay(display);
EGLCapabilities egl;
try (MemoryStack stack = stackPush()) {
IntBuffer major = stack.mallocInt(1);
IntBuffer minor = stack.mallocInt(1);
if (!eglInitialize(eglDisplay, major, minor)) {
throw new IllegalStateException(String.format("Failed to initialize EGL [0x%X]", eglGetError()));
}
egl = EGL.createDisplayCapabilities(eglDisplay, major.get(0), minor.get(0));
}
System.out.println("EGL caps created");
IntBuffer attrib_list = BufferUtils.createIntBuffer(18);
attrib_list.put(EGL_CONFORMANT).put(EGL_OPENGL_ES2_BIT);
//attrib_list.put(EGL_ALPHA_MASK_SIZE).put(4);
//attrib_list.put(EGL_ALPHA_SIZE).put(4);
//attrib_list.put(EGL_RED_SIZE).put(5);
//attrib_list.put(EGL_GREEN_SIZE).put(6);
//attrib_list.put(EGL_BLUE_SIZE).put(5);
//attrib_list.put(EGL_DEPTH_SIZE).put(4);
//attrib_list.put(EGL_SURFACE_TYPE).put(EGL_WINDOW_BIT);
attrib_list.put(EGL_NONE);
attrib_list.flip();
PointerBuffer fbConfigs = BufferUtils.createPointerBuffer(1);
IntBuffer numConfigs = BufferUtils.createIntBuffer(1);
boolean test2 = eglChooseConfig(eglDisplay, attrib_list, fbConfigs,numConfigs);
if (fbConfigs == null || fbConfigs.capacity() == 0) {
// No framebuffer configurations supported!
System.out.println("No supported framebuffer configurations found");
}
long test = numConfigs.get(0);
IntBuffer context_attrib_list = BufferUtils.createIntBuffer(18);
context_attrib_list.put(EGL_CONTEXT_MAJOR_VERSION).put(3);
context_attrib_list.put(EGL_CONTEXT_MINOR_VERSION).put(0);
context_attrib_list.put(EGL_NONE);
context_attrib_list.flip();
long context = eglCreateContext(eglDisplay,fbConfigs.get(0),EGL_NO_CONTEXT,context_attrib_list);
error = eglGetError();
surface = eglCreateWindowSurface(eglDisplay,fbConfigs.get(0),drawable,(int[])null);
error = eglGetError();
eglMakeCurrent(eglDisplay,surface,surface,context);
error = eglGetError();
GLESCapabilities gles = GLES.createCapabilities();
System.out.println("CLES caps created");
}
finally
{
unlock();
}
}
catch (Exception e)
{
System.out.println("JAWT Failed");
}
// Render with OpenGL ES
glClearColor(0f,0f,0f,1f);
glfwSwapInterval(vSync);
glEnable(GL_DEPTH_TEST);
int[] range = new int[2];
int[] precision = new int[2];
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, range, precision);
System.out.println("Window context Initialized");
}
Note that attribute lists can be whatever you want or nothing at all. I actually ran into GLES problem though when I didn't specify 3.0 as version compatibility for the context - it tried to use OpenGl ES-CL 1.1 for some reason and failed. Anyway, simply specifying minor and major context version fixed it.
Also note that it's the initialization only. JFrame and Canvas are created elsewhere and Canvas then passed to the Window class constructor.
Another important thing is the lock() / unlock() functions. You will get lots of XCB errors and crashes without them - because other threads will try to update display while you're drawing, causing conflicts and XCB will crash.
Also, you need to lock and unlock when you swap buffers (i.e. when you actually draw the framebuffer.
public void update()
{
try
{
lock();
eglSwapBuffers(eglDisplay, surface);
unlock();
}
catch (Exception e)
{
System.out.println("Swap buffers failed");
}
}
Don't mind that my current exception handling is lacking - I am editing my answer as soon as I found the solution lest my previous version confuses people.
I would also like to give credit to lwjgl-awt project, for giving me ideas. It does not support EGL as is, so I had to modify it a bit, but I took parts from there, so credit where credit is due.
https://github.com/LWJGLX/lwjgl3-awt
Just for comparison sake, here is the GLFW version. It's the initialization of the same class, basically, but it simply does other things. Here, however, the window is created directly inside the method.
public void Init()
{
System.out.println("Window init() started");
GLFWErrorCallback.createPrint().set();
if (!glfwInit()) {
throw new IllegalStateException("Unable to initialize glfw");
}
glfwDefaultWindowHints();
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
// GLFW setup for EGL & OpenGL ES
glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
windowHandle = glfwCreateWindow(width, height, title, NULL, NULL);
if (windowHandle == NULL) {
throw new RuntimeException("Failed to create the GLFW window");
}
System.out.printf("Window handle created %d\n", windowHandle);
SetCallbacks();
// EGL capabilities
displayHandle = glfwGetEGLDisplay();
System.out.printf("EGL DisplayHandle %d\n", displayHandle);
try (MemoryStack stack = stackPush()) {
IntBuffer major = stack.mallocInt(1);
IntBuffer minor = stack.mallocInt(1);
if (!eglInitialize(displayHandle, major, minor)) {
throw new IllegalStateException(String.format("Failed to initialize EGL [0x%X]", eglGetError()));
}
EGLCapabilities egl = EGL.createDisplayCapabilities(displayHandle, major.get(0), minor.get(0));
}
System.out.println("EGL caps created");
// OpenGL ES capabilities
glfwMakeContextCurrent(windowHandle);
System.out.printf("Current context: %d.%d rev %d, Client_Context: %d\n",glfwGetWindowAttrib(windowHandle,GLFW_CONTEXT_VERSION_MAJOR),
glfwGetWindowAttrib(windowHandle,GLFW_CONTEXT_VERSION_MINOR), glfwGetWindowAttrib(windowHandle,GLFW_CONTEXT_REVISION),
glfwGetWindowAttrib(windowHandle,GLFW_CLIENT_API));
GLESCapabilities gles = GLES.createCapabilities();
System.out.println("CLES caps created");
// Render with OpenGL ES
//glfwShowWindow(windowHandle);
glClearColor(0f,0f,0f,1f);
glfwSwapInterval(vSync);
glEnable(GL_DEPTH_TEST);
int[] range = new int[2];
int[] precision = new int[2];
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, range, precision);
System.out.printf("Current context: %d.%d\n",glfwGetWindowAttrib(windowHandle,GLFW_CONTEXT_VERSION_MAJOR),
glfwGetWindowAttrib(windowHandle,GLFW_CONTEXT_VERSION_MINOR));
}

Related

Java game keeps crashing after about 2 minutes of runtime (Intellij)

I am using Intellij to program Java.
I am currently trying to make a top down tile based shooter.
My issue is that my game, after approximately 2 minutes, crashes with a popup saying "Java(TM) Platform SE Binary has stopped working. I recorded the time it took for it to crash 3 times: 1m57s, 1m59s, 1m58s.
The game is in a very simple state right now and I am not sure what could be causing the crash. All of the relevant code is in just two classes: GameFrame.java (extends JFrame) and GamePanel.java (which extends JPanel).
GameFrame.java:
package net.magnusfrater.tds.game;
import javax.swing.*;
public class GameFrame extends JFrame {
public static final int width = 1000;
public static final int height = width / 16 * 10;
private GamePanel gp;
public GameFrame () {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(width,height);
setResizable(false);
setLocationRelativeTo(null);
setTitle("Time Based Fast Paced Top Down Shooter Demo");
gp = new GamePanel();
add(gp);
setVisible(true);
}
public static void main (String[] args) {
GameFrame gf = new GameFrame();
}
}
GamePanel.java
package net.magnusfrater.tds.game;
import net.magnusfrater.tds.input.Keyboard;
import javax.swing.*;
import java.awt.*;
public class GamePanel extends JPanel implements Runnable {
//panel
private Thread thread;
private static boolean running;
private boolean fpsLock;
//input
private Keyboard kb;
//game
private Game game;
public GamePanel () {
//panel
thread = new Thread(this, "Time Based Fast Paced Top Down Shooter Demo");
running = true;
fpsLock = true;
//input
//kb = new Keyboard();
//addKeyListener(kb);
//game
//game = new Game(1);
thread.start();
}
public void run () {
long iTimeNS = System.nanoTime();
int tickRate = 60;
long ns = 1000000000 / tickRate;
int ups = 0;
int fps = 0;
long iTimeS = System.nanoTime();
long s = 1000000000;
while (running) {
long fTimeNS = System.nanoTime();
if (fTimeNS - iTimeNS >= ns){
iTimeNS = System.nanoTime();
tick();
ups++;
if (fpsLock){
repaint();
fps++;
}
}
if (!fpsLock){
repaint();
fps++;
}
long fTimeS = System.nanoTime();
if (fTimeS - iTimeS >= s){
iTimeS = System.nanoTime();
System.out.println("ups: " + ups + "\tfps: " + fps);
ups = 0;
fps = 0;
}
}
System.exit(0);
}
public void tick () {
if (kb != null)
kb.tick();
if (game != null)
game.tick();
}
#Override
public void update (Graphics g) {
paint(g);
}
#Override
public void paint (Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(0,0,GameFrame.width, GameFrame.height);
//if (game != null)
//game.paint(g);
}
public static void quitGame () {
running = false;
}
}
I originally thought that the issue was because of the way that I was loading images for spritesheets or maybe the way I was loading text files for the level design but after reworking both of those, the issue remained.
That left me curious and a little bit fed up so I tried finding out more about the explanation for the crash. First I read more from the popup but it didn't say anything useful: (See below)
Second I looked at the exit code given by Intellij: (See below)
I looked up what exit code 255 was but there wasn't anything useful. The best explanation I could find was that exit code 255 meant that the real exit code was out of range: (See below)
I was out of ideas at this point so I just started plain old googling everything I could think of. The problem with googling "Java(TM) Platform SE Binary has stopped working" is that almost every suggested link is a question about Minecraft. Limiting my search to Stack Overflow yielded me some results, but nothing conclusive. Some of the fixes I found were stuff I already tried (such as not handling input streams properly, not handling buffered reader properly, not disposing of elements, etc). I found these links but none of them were truly related to my issue:
(See below)
(See below)
(See below)
(See below)
(See below)
(See below)
The last fix I tried was to re-install Java SE Development Kit 8u101 AND Java SE Development Kit 8u102. I then restarted Intellij. I then restarted my computer.
Nothing worked.
At this point I think I'm just dumb. I've overlooked something easy I can tell. What am I missing?
(ps~ This is a possibly related issue. So if I run my game with almost no content in it with the fps not locked to 60, I get really absurd numbers of frames per second. I didn't think that fps as high as 7,000,000 was possible. I think. I don't know. Have I programmed that wrong as well? Here is a related picture of my ups/fps output: [see below])
(SEE HERE) So Stack Overflow doesn't allow members with a score within a certain threshold post more than 2 links and allows absolutely no posting of images. So here is a link to a google doc with all of the links and images I mentioned above:
https://docs.google.com/document/d/1XrBuVio19GmkFz0EfRzXVp5AJmM5zPfVO6vK3oS3Eaw/edit?usp=sharing
Try and set your -Xmx to something like 2G and see if it runs longer. If so, something is allocating memory and maybe you have that other setting set that exits instead of garbage collecting for some reason.
Also, try changing your code to limit things using Guava's RateLimiter.
…
// class level
final RateLimiter frameLimiter = RateLimiter.create(60.0);
final RateLimiter outputLimiter = RateLimiter.create(1.0);
…
// in run method
while (running) {
frameLimiter.acquire();
repaint();
fps++;
if (outputLimiter.tryAcquire()){
System.out.println("fps: " + fps);
fps = 0;
}
}
I've removed ups and tick(). You should do your work after repainting and I don't think you want to do more work than needed for the next frame, which at the soonest should be at your max rate. Later you'll need to add logic to handle skipping work when frames are being skipped. I might make more sense to increment the fps within repaint.
You could put the output in its own thread and only acquire that limiter if you synchronized the increments and resetting of fps.

How to create an animated Image from still frames?

Given a list of true-color full frames in BufferedImage and a list of frame durations, how can I create an Image losslessly, that when put on a JLabel, will animate?
From what I can find, I could create an ImageWriter wrapping a ByteArrayOutputStream, write IIOImage frames to it, then Toolkit.getDefaultToolkit().createImage the stream into a ToolkitImage.
There are two problems with this attempt.
ImageWriter can only be instantiated with one of the known image encoders, and there is none for a lossless true-color animated image format (e.g. MNG),
It encodes (compresses) the image, then decompresses it again, becoming an unnecessary performance hazard.
[Edit]
Some more concise constraints and requirements. Please don't come up with anything that bends these rules.
What I don't want:
Making an animation thread and painting/updating each frame of the animation myself,
Using any kind of 3rd party library,
Borrowing any external process, for example a web browser,
Display it in some kind of video player object or 3D-accelerated scene (OpenGL/etc),
Work directly with classes from the sun.* packages
What I do want:
Frame size can be as large as monitor size. Please don't worry about performance. I'll worry about that. You'll just worry about correctness.
Frames all have the same size,
an Image subclass. I should be able to draw the image like g.drawImage(ani, 0, 0, this) and it would animate, or wrap it in an ImageIcon and display it on a JLabel/JButton/etc and it would animate,
Each frame can each have a different delay, from 10ms up to a second,
Animation can loop or can end, and this is defined once per animation (just like GIF),
I can use anything packaged with Oracle Java 8 (e.g. JavaFX),
Whatever happens, it should integrate with SWING
Optional:
Frames can have transparency. If needed, I can opaquify my images beforehand as the animation will be shown on a known background (single color) anyway.
I don't care if I have to subclass Image myself and add an animation thread in there that will cooperate with the ImageObserver, or write my own InputStreamImageSource, but I don't know how.
If I can somehow display a JavaFX scene with some HTML and CSS code that animates my images, then that's fine too. BUT as long as it's all encapsulated in a single SWING-compatible object that I can pass around.
You're right that ImageIO isn't an option, as the only animated format for which support is guaranteed is GIF.
You say you don't want to make an animation thread, but what about a JavaFX Animation object, like a Timeline?
public JComponent createAnimationComponent(List<BufferedImage> images,
List<Long> durations) {
Objects.requireNonNull(images, "Image list cannot be null");
Objects.requireNonNull(durations, "Duration list cannot be null");
if (new ArrayList<Object>(images).contains(null)) {
throw new IllegalArgumentException("Null image not permitted");
}
if (new ArrayList<Object>(durations).contains(null)) {
throw new IllegalArgumentException("Null duration not permitted");
}
int count = images.size();
if (count != durations.size()) {
throw new IllegalArgumentException(
"Lists must have the same number of elements");
}
ImageView view = new ImageView();
ObjectProperty<Image> imageProperty = view.imageProperty();
Rectangle imageSize = new Rectangle();
KeyFrame[] frames = new KeyFrame[count];
long time = 0;
for (int i = 0; i < count; i++) {
Duration duration = Duration.millis(time);
time += durations.get(i);
BufferedImage bufImg = images.get(i);
imageSize.add(bufImg.getWidth(), bufImg.getHeight());
Image image = SwingFXUtils.toFXImage(bufImg, null);
KeyValue imageValue = new KeyValue(imageProperty, image,
Interpolator.DISCRETE);
frames[i] = new KeyFrame(duration, imageValue);
}
Timeline timeline = new Timeline(frames);
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
JFXPanel panel = new JFXPanel();
panel.setScene(new Scene(new Group(view)));
panel.setPreferredSize(imageSize.getSize());
return panel;
}
(I don't know why it's necessary to set the JFXPanel's preferred size explicitly, but it is. Probably a bug.)
Note that, like all JavaFX code, it has to be run in the JavaFX Application Thread. If you're using it from a Swing application, you can do something like this:
public JComponent createAnimationComponentFromAWTThread(
final List<BufferedImage> images,
final List<Long> durations)
throws InterruptedException {
final JComponent[] componentHolder = { null };
Platform.runLater(new Runnable() {
#Override
public void run() {
synchronized (componentHolder) {
componentHolder[0] =
createAnimationComponent(images, durations);
componentHolder.notifyAll();
}
}
});
synchronized (componentHolder) {
while (componentHolder[0] == null) {
componentHolder.wait();
}
return componentHolder[0];
}
}
But that's still not quite enough. You first have to initialize JavaFX by calling Application.launch, either with an explicit method call, or implicitly by specifying your Application subclass as the main class.
something like
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(getImageForCurrentTime(), 3, 4, this);
}

Can't stop flickering on JPanel

I have class that creates a new thread.
`
public ScreenG(JPanel PanelR)
{
Panel = PanelR;
RenderImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
FPS = 25;
Hide = false;
(new Thread()
{
public void run()
{
while(true)
{
if(Hide == false)
{
Timer = System.currentTimeMillis() + (1000/FPS);
if(!DrawRendering)
{
Graphics g = Panel.getGraphics();
g.drawImage(RenderImage, 0, 0, null);
}
DrawRendering = false;
while(System.currentTimeMillis() <= Timer) try { Thread.sleep(1); } catch (InterruptedException e) {Thread.currentThread().interrupt();}
}
}
}
}).start();
}
public void draw(BufferedImage ImageR)
{
DrawRendering = true;
RenderImage = ImageR;
Graphics g = Panel.getGraphics();
g.drawImage(RenderImage, 0, 0, null);
}`
In my main I create a new instance of ScreenG. This will start a new thread that draws a bufferedImage onto a JPanel with a consistent FPS.
In the main I would then call draw with the image that I created. Sometimes it works but sometimes the image on the panel flickers. I try variations like the draw function taking over the drawing. Non of them work. I could only REDUCE the flickering.
Not possible by design. Swing does not synchronize to the bitmap raster DMA that's actually sending the screen data to your monitor, so it always possible that the screen buffer is read by the DMA while you're busy rendering to it (possible exception is Fullscreen mode).
To at least minimize flickering follow the recommended method of custom Swing painting: https://docs.oracle.com/javase/tutorial/uiswing/painting/
You can easily trigger periodic repaints on the EDT using a Swing timer, or SwingUtilities.invokeAndWait/invokeLater from another thread (whatever works best in your design).
The flickering can be because the rendering isn't fast enough from an update.
Now I do recommend you use Swings paintComponent (Graphics g) when rendering its components. That being said. To solve the flickering for you add a BufferStrategy in your JFrame
Without that code avaible I can only provide a general solution.
JFrame jframe = new JFrame ();
...
BufferStrategy bufferstrategy = jframe.getBufferStrategy ();
if (bufferstrategy == null) {
jframe.createBufferStrategy(3);
return;
}
g.dispose();
bufferstrategy.show();
To read more about BufferStrategy I recommend a read over at the documentation.
Small Note
There is no reason in your code to either store JPanel PanelR or BufferedImage ImageR. You can instead directly invoke methods directly on PanelR resp. ImageR.
Thank you for the answers. I read Oracle tutorial that you recommended and get my paintComponent() function working correctly on the main thread. To do that I am calling JPanel().repaint() from the draw() function. I will learn about using BufferStrategy next.

Programmatically control the size of a SWT IViewPart

I realise that this is somewhat of an unusual request, since most ViewParts layed out by the workspace and may be in stacks and not have unilateral access to their own size.
However, what i am trying to do is slightly different. I am extending a find-replace bar for eclipse that is reminiscent of the one you see in firefox (and much less obtrusive than the default).
So the desire for this is for it to be a fixed size at the bottom of the editor pane. However, I have not succeeded in setting the size of my view. I have tried
using an ISizeProvider:
public int getSizeFlags(boolean width) {
if (width) {
return SWT.FILL;
}
return SWT.MIN | SWT.MAX;
}
#Override
public int computePreferredSize(boolean width, int availableParallel,
int availablePerpendicular, int preferredResult) {
if (width) {
return preferredResult;
}
return fixedHeight;
}
calling setSize() on my root pane and on its parent pane (NB it is not surprising this doesn't work because the parent's layout manager will likely override it).
Using the internal PartPane class to get the bordering sashes to attempt to move IT programattically. (Don't flame me for doing this, I am just trying to explore the possibilities).
private void updateSize(IWorkbenchPartReference pPartRef) {
// FIXME -- this is all internal stuff. is there a public way to do this?
if (pPartRef instanceof WorkbenchPartReference) {
PartPane lPane = ((WorkbenchPartReference) pPartRef).getPane();
Sashes sashes = new Sashes();
if (lPane.getContainer() != null) {
lPane.getContainer().findSashes(lPane, sashes );
Sash topSash = sashes.top;
if (okToUse(topSash)) {
Rectangle parentBounds = topSash.getParent().getBounds();
int topSashTop = parentBounds.height - fixedHeight - topSash.getSize().y;
sashes.top.setLocation(sashes.top.getLocation().x, topSashTop);
topSash.getParent().layout();
System.out.println("sashtop = " + topSashTop);
}
}
}
}
I've also tried calling PartPane.flushLayout() and PartPane.getContainer.resizeChild() and none of these do anything.
None of this works. Is there a way to achieve what I want?

How do I set the position of the mouse in Java?

I'm doing some Swing GUI work with Java, and I think my question is fairly straightforward; How does one set the position of the mouse?
As others have said, this can be achieved using Robot.mouseMove(x,y). However this solution has a downfall when working in a multi-monitor situation, as the robot works with the coordinate system of the primary screen, unless you specify otherwise.
Here is a solution that allows you to pass any point based global screen coordinates:
public void moveMouse(Point p) {
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] gs = ge.getScreenDevices();
// Search the devices for the one that draws the specified point.
for (GraphicsDevice device: gs) {
GraphicsConfiguration[] configurations =
device.getConfigurations();
for (GraphicsConfiguration config: configurations) {
Rectangle bounds = config.getBounds();
if(bounds.contains(p)) {
// Set point to screen coordinates.
Point b = bounds.getLocation();
Point s = new Point(p.x - b.x, p.y - b.y);
try {
Robot r = new Robot(device);
r.mouseMove(s.x, s.y);
} catch (AWTException e) {
e.printStackTrace();
}
return;
}
}
}
// Couldn't move to the point, it may be off screen.
return;
}
You need to use Robot
This class is used to generate native system input events for the purposes of test automation, self-running demos, and other applications where control of the mouse and keyboard is needed. The primary purpose of Robot is to facilitate automated testing of Java platform implementations.
Using the class to generate input events differs from posting events to the AWT event queue or AWT components in that the events are generated in the platform's native input queue. For example, Robot.mouseMove will actually move the mouse cursor instead of just generating mouse move events...
Robot.mouseMove(x,y)
Check out the Robot class.
The code itself is the following:
char escCode = 0x1B;
System.out.print(String.format("%c[%d;%df",escCode,row,column));
This code is incomplete by itself, so I recommend placing it in a method and calling it something like 'positionCursor(int row, int column)'.
Here is the code in full (method and code):
void positionCursor(int row, int column) {
char escCode = 0x1B;
System.out.print(String.format("%c[%d;%df",escCode,row,column));
}

Categories

Resources