Swing tooltip resizable - swing

I've tried to implement a resizeable tooltip but have some problems with this.
When the tooltip is shown, the text updates on change in the model (implemented with property change listener). What I need now is, that the tooltip changes its size as well depending on the text.
Tried revalidate, doLayout and repaint but with no effect. The tooltip doesn't change its size.
Only moving the mouse gives me a correct sizing for the first text which is displayed in the tooltip.
Can anybody help?
Here are some code snippets: first of all my tolltip class:
public class ResizeableToolTip extends JToolTip {
public ResizeableToolTip(final JComponent component) {
super(component);
initComponents();
}
#Override
protected void initGUI() {
super.initGUI();
setLayout(new BorderLayout());
}
/**
* Component initialization goes here...
*/
private void initComponents() {
setTipText(getComponent().getToolTipText());
setPreferredSize(calculateOptimalSize());
}
private abstract Dimension calculateOptimalSize();
#Override
public void setTipText(String tipText) {
super.setTipText(tipText);
setPreferredSize(calculateOptimalSize());
revalidate();
}
}
Then I have a button which is using this implementation:
public class MyButton extends JButton implements PropertyChangeListener {
//...
private ResizeableToolTip tooltip;
//...
private initComponents() {
//...
tooltip = new ResizeableToolTip(this);
//...
}
//...
public void propertyChange(final PropertyChangeEvent pcevt) {
//...
if (MyButtonModel.TOOLTIPTEXT_PROPERTY.equals(pcevt.getPropertyName()) {
tooltip.setTiptext((String) pcevt.getNewValue());
tooltip.repaint();
}
//...
}
//...
}
The result should be a tooltip which is displayed over the button where the text is changing when s.th. changes in the data model. The text changes are working but the size of the box of the tooltip stays on the wrong size.

As far as i can tell there is not way to resize it besides moving the mouse. However the component should have one mouse mouse motion listener so all you have to do is call mouseMoved on that and it will think the mouse has been moved and will resize the tooltip.
//comp will be whatever component your tooltip is on
if(comp.getMouseMotionListeners().length > 0)comp.getMouseMotionListeners()[0].mouseMoved(new MouseEvent(inst, MouseEvent.MOUSE_MOVED, System.currentTimeMillis(), 0, MouseInfo.getPointerInfo().getLocation().x, MouseInfo.getPointerInfo().getLocation().y, 0, false));
Just call that after you set the tooltip and it should resize.

Related

How to expand the view while zooming an image into ViewPager2

I was trying, with ViewPager2, to get default gallery-like experience of common Android SmartPhone, where you can zoom an image with pan and pinch controls along with the ability to navigate to another photo by swipe gestures.
I faced a problem in which when the zoomed image is swiped expecting it to get panned, instead of that, the ViewPager2 switched to another page.
ViewPager2 responds to the swipe event and causes page change and it doesn’t let zoomable view to respond to that event.
How do I solve the problem? Thanks.
The only solution I found is to use the old ViewPager with which it is possible to intercept events and if the photo is enlarged, it is possible to disable the page change and allow the management of the zoom.
First I defined a field, in a static class, to keep track of the state the photo is in:
public class Utilities {
....
static boolean isZoomed;
private Utilities () { }
static public void setIsZoomed (boolean z) {
isZoomed = z;
}
static public boolean getIsZoomed () {
return isZoomed;
}
....
}
Then in the custom class for managing the zoom I detect the status of the photo:
public class TouchImageView extends ImageView {
...
Utilities.setIsZoomed(normalizedScale != 1);
...
}
Finally, in the ViewPager custom class I disable or allow pagination based on the state of the photo:
public class CustomViewPager extends ViewPager {
public CustomViewPager (Context context) {
super(context);
}
public CustomViewPager (Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onInterceptTouchEvent (MotionEvent ev) {
try {
if (Utilities.getIsZoomed())
return false;
else
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException e) {
return false;
}
}
}

Some Actions do not work

I want to make a text appear in the center of the screen, indicating
the current level. It should appear gradually and after a while disappear gradually. I'm using scene2d with stages, actors.. so i would use Actions.
This is what i have now:
public class TextActor extends Actor {
private BitmapFont font;
private CharSequence charSequence;
public TextActor(CharSequence charSequence) {
font = new BitmapFont(Gdx.files.internal("fonts/white_standard_font.fnt"));
this.charSequence = charSequence;
}
#Override
public void act(float delta) {
super.act(delta);
}
#Override
public void draw(Batch batch, float delta) {
super.draw(batch, delta);
font.draw(batch, charSequence, getX(), getY());
}
}
In the class that creates the TextActor..
textActor.addAction(Actions.sequence(Actions.fadeIn(1f), Actions.delay(1f), Actions.fadeOut(1f), new Action() {
#Override
public boolean act(float delta) {
textActor.remove();
transitionInProgress = false;
gameState = GameState.RUNNING;
Gdx.input.setInputProcessor(stage);
return true;
}
}));
gameTable.addActor(textActor);
fadeIn, fadeOut, alpha.. don't work. I tried with "moveBy" and it works, so it seems a problem concerning the appearance of the Actor. There is something that escapes me.
The fade actions modify the alpha value of the Actor's color (getColor().a). You're drawing the font directly without applying the color associated with the actor.
Take a look at how Label.draw is implemented for a better understanding. In the meantime, just try adding this above your font.draw(...) call:
font.setColor(getColor())
Or, if you don't want to modify the entire color, just the alpha, try this:
font.getColor().a = getColor().a;
UPDATE:
Also note that you should apply the parentAlpha (second parameter of draw - labelled as delta in your example) to the final alpha:
font.getColor().a = getColor().a * parentAlpha
This allows your actor to fade if you change the alpha of the stage or any parents.

Change Button scale on click

I want for all the Buttons in my game to scale down when user touch down the button and goes back to normal scale as soon as on touch up.What should be be the best possible way.Just like functionality of button in COCOS-2d.
I don't want to use extra small image for button down,if there is other alternative without using extra image.?
Second one is to produce some sound on click,I don't want to this in input listener of every button since sound is same for all buttons.How should i implement this in best possible way.
Thanks in advance.
// i just implement my custom class ,is there is other good way to implement.
public class ImprovedButton extends Button {
boolean isTouchDown=false;// is touch begin
float originalWidth,originalHeight; //actual size
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
if( isPressed()) {
if (!isTouchDown) {
//play sound if any
isTouchDown=true;
originalHeight=getHeight();
originalWidth=getWidth();
setWidth(originalWidth*.95f);
setHeight(originalHeight*.95f);
}
}
else { //pressing is stopper if any
if (isTouchDown) {
isTouchDown=false;
setWidth(originalWidth);
setHeight(originalHeight);
}
}
}
}
one problem with this code is,pivot of scaling bottom left corner.How to set it as center.
I do the same thing on my games.
Make like your custom class for the button.
If you want you can increase the scale in the update method, so the button will scale smooth.
Look here, I wrote for you a example
public class CoolButton {
private Sprite sprite; // the sprite that we are going to use to draw our button
private float scale; // the scale of the button, 1 = full scale, 0.5 half, 2 = twice bigger, etc
public CoolButton(Texture texture, float x, float y, float width, float height) {
sprite = new Sprite(texture);
sprite.setPosition(x, y);
sprite.setSize(width, height);
sprite.setOriginCenter();
scale = 1;
}
public void draw(SpriteBatch batch) {
sprite.setScale(scale); // setting the scale and drawing the button
sprite.draw(batch);
}
// this method should be called when the user touches the screen (don't forget to unproject the coords)
public boolean touchDown(float x, float y) {
if (sprite.getBoundingRectangle().contains(x, y)) { // if the button is touched
scale = 0.7f;
return true;
}
return false;
}
// when you release the touch from the screen make the button back to its normal size
public void touchUp() {
scale = 1f;
}
}
If you have any question please comment here.
Here is a custom class ImprovedButton extends from Button class has additional functionality of Change in SCALE of button and plays SOUND on click .
There is also a class of ImprovedButtonStyle has paramter of scale and sound.
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.ui.Button;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
public class ImprovedButton extends Button {
boolean isPressedOnce=false;//is press started or touchDown
float originalWidth,originalHeight;
private ImprovedButtonStyle istyle;
public ImprovedButton() {
super();
this.istyle=new ImprovedButtonStyle();
}
public ImprovedButton(Actor child, ImprovedButtonStyle style) {
super(child, style);
this.istyle=style;
}
public ImprovedButton(Actor child, Skin skin, String styleName) {
this(child,skin.get(styleName, ImprovedButtonStyle.class));
}
public ImprovedButton(Actor child, Skin skin) {
this(child,skin.get(ImprovedButtonStyle.class));
}
public ImprovedButton(ImprovedButtonStyle style) {
super(style);
this.istyle=style;
}
public ImprovedButton(Drawable up, Drawable down, Drawable checked) {
super(up, down, checked);
istyle=new ImprovedButtonStyle();
}
public ImprovedButton(Drawable up, Drawable down) {
this(up, down,null);
}
public ImprovedButton(Drawable up) {
this(up,null,null);
}
public ImprovedButton(Skin skin, String styleName) {
super(skin, styleName);
this.istyle=skin.get(ImprovedButtonStyle.class);
}
public ImprovedButton(Skin skin) {
super(skin);
setStyle(skin.get(ButtonStyle.class));
}
#Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
if( isPressed()) {
if (!isPressedOnce) {
if (istyle.sound!=null) {
istyle.sound.play();
}
isPressedOnce=true;
originalHeight=getHeight();
originalWidth=getWidth();
setWidth(originalWidth-istyle.changeInWidth);
setHeight(originalHeight-istyle.changeInHeight);
}
}
else {
if (isPressedOnce) {
isPressedOnce=false;
setWidth(originalWidth);
setHeight(originalHeight);
}
}
}
#Override
protected void drawBackground(Batch batch, float parentAlpha, float x,float y) {
int offsetX=0;
int offsetY=0;
if(isPressed()){
offsetX=istyle.changeInWidth/2;
offsetY=istyle.changeInHeight/2;
}
super.drawBackground(batch, parentAlpha, x+offsetX, y+offsetY);
}
public static class ImprovedButtonStyle extends ButtonStyle{
public int changeInWidth=2,changeInHeight=2;
public Sound sound=null;
public ImprovedButtonStyle() {
super();
}
public ImprovedButtonStyle(ButtonStyle style,int changeInWidth,int changeInHeight,Sound sound) {
super(style);
this.changeInHeight=changeInHeight;
this.changeInWidth=changeInWidth;
this.sound=sound;
}
public ImprovedButtonStyle(Drawable up, Drawable down, Drawable checked) {
super(up, down, checked);
}
public ImprovedButtonStyle(ImprovedButtonStyle style) {
super(style);
this.changeInHeight=style.changeInHeight;
this.changeInWidth=style.changeInWidth;
this.sound=style.sound;
}
}
}

NotSerializableException for ToolkitImage when serializing a model in Swing

I have Swing application which manipulate shapes. In my toolbar I have a zoom function that the user activate by clicking on a button, then the cursor of the mouse changes to a magnifier which is an image.
My problem is actually the cursor, for some raisons, when I set the cursor on the panel displaying the shapes, I can't save my model and I get the java.io.NotSerializableException: sun.awt.image.ToolkitImage exception.
My model
public class Document implements IDocObservable,Serializable{
...
public void updateCursor() {
Iterator<IDocObserver> iter = docObservers.iterator();
while (iter.hasNext()) {
iter.next().docCursorChanged();
}
}
...
}
The action
public class ZoomInAction extends AbstractAction {
public void actionPerformed(ActionEvent arg0) {
...
Application.getInstance().getActiveDocument().updateCursor();
}
}
The display Panel (note : if I comment the setCursor(..) line, I'am able to save )
public class Window extends JPanel implements IDocObserver{
...
public void paint(Graphics g){
//drawing the differents shapes
}
#Override
public void docCursorChanged() {
setCursor(Utile.getZoomInCursor();
}
}
}
The class that provide the cursor
public class Utile {
private static Image zoomIn = toolkit.getImage(Utile.class.getResource("/images/zoomin_mouse.png"));
...
public static Cursor getZoomInCursor() {
return toolkit.createCustomCursor(zoomIn, hotSpot, "");
}
}
The writing of the object is a standard Java methode with outStream.writeObject(doc);
thanks
You aren't just serializing a model, you are serializing a list of IDocObservers, which includes Window extends JPanel implements IDocObserver. IOW you are serializing a JPanel. Don't do that: see the warning at the top of the Javadoc. You don't need to save the observers along with the observable, surely: can't you make that list transient?

Java Swing - Display table in sub menu

I have a menu that displays say
Item1
Item2
Item3
etc. Clicking on Item1 should display me a Table with 2 columns.
I tried something below with displaying just a label. But the label gets displayed somewhere in the screen where as I am expecting it to be a submenu under menuitem1.
JMenu mainMenu = new JMenu("MainMenuHeader");
JMenu menuItem1 = new JMenu(new SomeClassExtendingAbstractAction("menuItem1"));
public class SomeClassExtendingAbstractAction extends AbstractAction {
public SomeClassExtendingAbstractAction(String displayText) {
super(displayText);
}
public void actionPerformed(ActionEvent event) {
try {
SubMenuDialog.showDialog(parent);
} catch (Throwable e) {
}
}
}
public class SubMenuDialog extends JDialog {
public SubMenuDialog(JFrame parent) {
super();
initialize();
}
private void initialize() {
JLabel label = new JLabel();
label.setText("This is test submenu");
getContentPane().add(label);
}
public static void showDialog(JFrame parent) {
SubMenuDialog subMenuDialog = new SubMenuDialog(parent);
subMenuDialog.pack();
subMenuDialog.setVisible(true);
}
}
If I understand correctly, what you want to do is to show arbitrary component in a submenu popup. You obviously cannot use JDialog as it would give you a, you know, JDialog.
Your SubMenuDialog#showDialog can create a JPopupMenu, add any component to it (for example JScrollPane containing a table, or JPanel with labels), and show it where a normal submenu would be.
However it's not a good idea in general to show complicated things in a popup, since it's too easy to lose the popup, plus you may get focus problems with components inside the popup.
I'd suggest you consult a UI designer for the best UI representation of the functionality you want to implement.