I am dealing with JEditorPane to display HTML documents and I created a button which scroll me to next view port every time I click it, "as if I am turning a page of a book".
However, sometimes I see a part of a line at the top of the view port, so is there any way to force JScrollBar to scroll to ahead of a line?
I tried setBlockIncrement() member method but it didn't work at all.
Here you are my best attempt:
//get the visible rectangle as well as the most bottom right point.
Rectangle rec = jEditorPane1.getVisibleRect();
Point pt = new Point((int)rec.getX() +(int)rec.getWidth(),(int)rec.getY() + (int)rec.getHeight());
// get the offset of the most bottom right point
int off = jEditorPane1.viewToModel(pt);
try {
//get next viewable rectangle and scroll to it
rec = jEditorPane1.modelToView(off+100);
rec.height = jEditorPane1.getVisibleRect().height;
jEditorPane1.scrollRectToVisible(rec);
} catch (BadLocationException ex) {
Logger.getLogger(NewJFrame2.class.getName()).log(Level.SEVERE, null, ex);
}
Guess you have a position in the Document you want to show. You can get visible rect of the position using modelToView() method. and use the y position to set your viewport. E.g. use scrollRectToVisible passing the y and viewport height in the rectangle parameter.
Related
I am trying to set restrictions on the movement of a camera in JavaFX such that when it moves, it does not allow the user to move in such a way that only the content of the subscene is visible. Currently, my movement code looks as follows and has no checks to prevent this, I have tried limiting the movement of the camera by checking its coordinates and approximating if it will or will not show the content of the subscene, but that has problems in that it is purely an approximation and when zooming. TLDR, the problem involves 1 detecting when the camera moves away from the content of it, and 2 preventing a transformation from occurring if it will result in the camera moving away from the content.
mapView.addEventFilter(MouseEvent.MOUSE_PRESSED, e->{
startX = e.getX();
startY = e.getY();
});
mapView.addEventFilter(MouseEvent.MOUSE_DRAGGED, e -> {
camera.setTranslateX(camera.getTranslateX() + (startX - e.getX()));
camera.setTranslateY(camera.getTranslateY() + (startY - e.getY()));
});
mapView is a MeshView if that is relevant.
If you would like me to clarify anything or need further information I will provide it. Thanks for the help and good day.
The camera has a viewport that you can imagine as a movable overlay above the contents (with some background being displayed in areas where no contents are placed). For the sake of simplicity, I would separate scrolling (i.e. moving the viewport) from content transformations (e.g. zooming).
Based on this mental model, you can define the scrollable bounds to be the bounds of your contents as well as a possibly empty portion of the current viewport (e.g. in case of contents smaller than viewport). The scrollable bounds needs to be recomputed after every scroll operation (increasing/reducing empty space within the current viewport) or content manipulation (transformations and bounds changes). If you restrict scrolling to the scrollable bounds, then you can ensure that empty space within the viewport is never increased by a scroll operation.
You can create an ObjectBinding scrollableBounds that is bound to the contents' bounds-in-local and local-to-parent-transform properties, as well the viewport-bounds. Then you can create a scollableBoundsProperty that is bound to the binding. That property can be accessed when scrolling to restrict the translation before applying it, thus preventing an increase of empty space within the viewport.
ObjectBinding<Bounds> scrollableBoundsBinding = new ObjectBinding<>() {
{
// TODO: bind to dependencies: viewport bounds and content bounds
// TODO: (transformed to the same coordinate system)
bind(camera.boundsInParentProperty(),
contentPane.boundsInLocalProperty(),
contentPane.localToParentTransformProperty());
}
#Override protected Bounds computeValue() {
// TODO: compute union of viewport and content bounds
return unionBounds(viewportBounds, contentBounds);
}
};
ObjectProperty<Bounds> scrollableBoundsProperty = new SimpleObjectProperty<>(
scrollableBoundsBinding);
// ...
// on mouse drag:
// dx, dy: relative mouse movement
// tx, ty: current scrolling
// mintx, maxtx, minty, maxty: translation range
// (taken from scrollable bounds and viewport size)
if (dx < 0) { tx = max(mintx, tx + dx); }
else { tx = min(maxtx, tx + dx); }
if (dy < 0) { ty = max(minty, ty + dy); }
else { ty = min(maxty, ty + dy); }
You might want to further restrict scrolling when the contents fully fit within the viewport, e.g. by placing the contents at the top left corner. You could also restrict the minimal zoom level in that case so that the contents are displayed as big as possible.
Note on usability: As already pointed out by another answer, you might want to consider allowing to drag over the contents by a bit, possibly with decreasing efficiency the further away one tries to scroll from the contents, comparable to the behavior of scrolling via touchpad in Safari. Then, when the interaction finishes, you could transition back instead of snapping in order to restrict the viewport to the contents again.
that's pretty common: just move and after you moved check if you're out of bounds... in that case go back into scene... this usually feels natural as when you try to pan an image on your phone.. it doesn't just block: it appears as it's making resistance and when you end your gesture it goes back... that's the simplest thing to do
I'm creating simple app i have Tree object where i store filenames when user choose one SWTImageCanvas.loadImage(path) is being called. Every image has some points defined so points are displayed as gc.fillOval. When user move mouse over oval it name is being displayed i achive this by setting some additional variable and using SWTImageCanvas.redraw() method. Such redrawing cause blinking of canvas so i thought about double buffering i have read some tutorials about it but when i'm trying to run it my image is hovered by white layer with ovalls on it here is my drawing function
private void drawStations(Event e) {
Rectangle clientRect = mainSWTImageCanvas.getClientArea();
if(mainSWTImageCanvas.getSourceImage()!=null)
{
if(mainSWTImageCanvas.getScreenImage()!=null)
mainSWTImageCanvas.getScreenImage().dispose();
Image screenImage = new Image(mainSWTImageCanvas.getDisplay(),clientRect.width,clientRect.height);
this.gc = new GC(screenImage);
//drawing ovals on gc
.
.
.
this.gc.drawImage(screenImage, 0, 0);
this.gc.dispose();
e.gc.drawImage(screenImage, 0, 0);
}
It turns out that double buffering in swt display can by done by passing SWT.DOUBLE_BUFFERED in constructor.
I'm trying to take a window screenshot to use that as background in the application.
This is my code:
try {
Robot robot = new Robot();
Rectangle captureSize = new Rectangle(new MainWindow().getX(), new MainWindow().getY(), MainWindow.getWIDTH(), MainWindow.getHEIGHT());
RenderManager.backgroundGUIs = robot.createScreenCapture(captureSize);
GUIManager.ThisGui = new GUI("inventory", null, false);
} catch(AWTException e) {
System.err.println("Error taking screenshot!");
}
And these are the MainWindow().getY() and MainWindow().getX() methods:
public int getX() {
return (int) frame.getLocationOnScreen().getX();
}
public int getY() {
return frame.getY();
}
Now... it works fine, but there is a problem. frame.getLocationOnScreen().getX() and frame.getX() return the location with the window border, that hasn't to be in the screensot. Ok, i can manually calculate border size to subtract it, but from Windows 7 to Windows 8, from Windows 8 to Mac, etc. window border changes.
So... is there a method to get frame position or window border size to calculate what i need?
Thank you for your time and your answer!
As simple as this:
x = frame.getRootPane().getX();
As well, you can make all other calculations according to the root pane, just dropping the frame's.
As expected, the root pane is the top-level container inside any Frame/Window/Dialog etc. It includes the menubar too.
Use this
frame.getContentPane().getSize();
Check out the Screen Image class. You can create an image of any component displayed on the frame.
So you could use frame.getRootPane() as the component you want the image of.
Or frame.getContentPane() if you don't want the menu bar. I think this method returns a Container object so you will need to cast is to a JComponent.
int mouseX = MouseInfo.getPointerInfo().getLocation().getX() - frame.getX() - frame.getRootPane().getX();
int mouseY = MouseInfo.getPointerInfo().getLocation().getY() - frame.getY() - frame.getRootPane().getY();
This gives the top right point within the border / tab of a frame
I'm developing a touch based windows 7 app using a tuio client-server setup and a touch library that extends multitouch 4 java.
One of the functionality I'm struggling with is to enable text highlighting when using touch.
I display a simple txt file using a JTextPane to display the text, the highlighting is done by through a drag action.
I get the clicked position where the drag event starts and then when it stops and tried to convert those coordinates to the text panel's space but I get different values from the ones that I should have, usually before the actual text.
The code I'm using to display the document is the following:
//Create the JDialog that is the container of it
window = new JDialog(parent);
window.setUndecorated(true);
//Create the JTextPane
text = new JTextPane();
text.setPage(newFile.toURI().toURL());
text.setEditable(false);
text.setHighlighter(null);
//ScrollPane that will be used to display the text
JScrollPane scroll = new JScrollPane(text);
scroll.setPreferredSize(new Dimension(500, 700));
window.getContentPane().add(scroll, BorderLayout.CENTER);
window.pack();
window.setVisible(true);
window.validate();
Where the JDialog parent is the main display component used in my app.
The drag is handled as follows:
#Override
public boolean processGestureEvent(GestureEvent ge) {
if((ge instanceof DragEvent) && this.component.isHighlight())
{
tapCount=0;
if(this.component.isHighlight())
{
//do highlighting
DragEvent drag = (DragEvent) ge;
switch (drag.getId()) {
case GestureEvent.GESTURE_STARTED:
Point start = drag.getFrom();
Point calcStart = new Point(start.x - compPosition.x, start.y - compPosition.y);
startPos = this.textDisplay.viewToModel(calcStart);
break;
case GestureEvent.GESTURE_ENDED:
Point end = drag.getTo();
Point calcEnd = new Point(end.x - compPosition.x, end.y - compPosition.y);
endPos = this.textDisplay.viewToModel(calcEnd);
System.out.println("I have this positions:" + startPos + "/" + endPos);
System.out.println("Should have " + this.textDisplay.getSelectionStart() + "/" + this.textDisplay.getSelectionEnd());
System.out.println("And the text is: " + this.textDisplay.getText().substring(startPos, endPos));
break;
case GestureEvent.GESTURE_CANCELED:
startPos = 0;
endPos = 0;
break;
}
}
return true;
}
In which the compPosition is the JDialog's position that holds the text pane. I'm simulating touch with the mouse so the correct text position for the highlighting I'm getting from the built-in highlighting functionality of the text pane with mouse.
Is the problem because of the JDialog and the JScroll pane that somehow skews the conversion?
The coordinate system for the point's I get from the touch are with the origin in the top left corner of the screen and the text pane's coordinate system origin is in the same top lef corner.
Any ideas on how can I solve the problem? Any suggestions are appreciated.
LE:
I was doing something wrong in that I was adding the gesture processor when I initialized the component and it's position was (0,0) and only afterwards I moved it where I wanted to.
I changed the position calculations as follows:
Point calcStart = new Point(start.x - this.component.getLocation().x, start.y -this.component.getLocation().y);
passing instead a reference to the actual component and getting the location when needed.
try instead of
Point calcStart = new Point(start.x - compPosition.x, start.y - compPosition.y);
to use
Point calcStart = new Point(start.x, start.y);
i wonder how it gonna end, so give us some value of what you get
I just can't figure this, and I am pulling my hair out right now!!
I have a Stage with a Label added to it, I set everything up and the first time I call Stage.draw() everything works fine. However, as soon as I set the text of the Label nothing gets drawn. Funny thing is, when I don't change the text it draws perfectly as expected, but when I call label.setText("THE TEXT") it just doesn't draw.
I have stepped through my code and I have noted down the height, width, x and y values before and after setting text of the Label, and they are all the same (before and after).
Also, when I draw the Stage it's drawn above a Sprite, and positioning the Sprite is based on the Label's position.
The Sprite draws fine before I set text on the Label and after.
PS: I have also made sure that the Sprite is not drawn "over" the Label.
This is my setup:
I have a MainGame class that renders a Player class, when ever the back button is pressed the Sprite with the Stage gets drawn, or should get drawn.
spriteBatch.begin();
player.update(spriteBatch, delta);
spriteBatch.end();
// the pause menu is drawn with a separate sprite batch as it needs to be in middle relative to the screen and above everything else
if (player.isPaused()){
messageSpriteBatch.begin();
messageSprite.draw(messageSpriteBatch);
messageSpriteBatch.end();
messageStage.draw(); // the stage doesn't seem to be getting drawn
}
Player class - update method
if (!paused){
// removed for clarity
}else{
// on MainGame class we render a small box with one of the following messages
// READY
// PAUSE
// QUIT?
// GAME OVER
if (Gdx.input.justTouched()){
paused = false;
}
spriteBatch.setProjectionMatrix(camera.combined);
camera.update();
}
messageSpriteBatch = new SpriteBatch();
messageStage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
messageFont = new BitmapFont(Gdx.files.internal("fonts/fontfile.fnt"));
messageStyle = new LabelStyle();
messageStyle.font = messageFont;
messageLabel = new Label("READY", messageStyle);
This is how I initialise my Label, Sprite and Stage:
float fontScaleX = Gdx.graphics.getWidth()/SCALE_X_DIVIDER;
float fontScaleY = Gdx.graphics.getHeight()/SCALE_Y_DIVIDER;
messageLabel.setFontScale(fontScaleX*1.4f, fontScaleY*4.2f);
messageLabel.setPosition((messageStage.getWidth()/2)-((messageLabel.getWidth()/2)*messageLabel.getFontScaleX()), (messageStage.getHeight()/2)-((messageLabel.getHeight()/2)*messageLabel.getFontScaleY())+(player.getScoreboard().getSize().y/2));
messageStage.addActor(messageLabel);
messageStage.act();
messageTexture = new Texture(Gdx.files.internal("images/message_background.png"));
messageSprite = new Sprite(messageTexture);
messageSprite.setSize((messageLabel.getWidth()*messageLabel.getFontScaleX())*1.5f, (messageLabel.getHeight()*messageLabel.getFontScaleY())*3);
messageSprite.setPosition(messageLabel.getX()-(messageSprite.getWidth()/6), messageLabel.getY()-messageSprite.getHeight()/2);
Please help me, before I get bald xD
Well the width and height of the label is usually set once when creating the Label, matching the width and height of the initial text passed to the Constructor. You of course can make it bigger by setting the width and height later on. Then you could also use alignments by the way...
Are you using any special characters when changing the text, so the font has a problem with that?
Maybe posting some code could give more insights...
Haha, well, I found out what was up, it was my font file, you see when I was editing it, I used the text READY, so when I saved it, I didn't know that the text written is what is saved, so when I looked at the font.png file, I found that it only contained the letters ADERY.
Thanks for the help anyway =]