How can I create a JComboBox that has zero width border? - swing

I want to display a "table" where a JLabel is right justified in column 1 and a component is left justified in column 2 for each row. I've been able to make it look good when the column 2 components are JLabel, JTextField, and JCheckBox. But I'm understandably having trouble with JComboBox.
I see two ways (possibly three) to solve the problem.
increase the left inset for the non-JComboBox components
zero the insets for all components and let the layout manager handle gaps
fiddle with the UIManager to zero the JComboBox insets?
The #2 option seemed like an easier approach to understand, implement, and maintain until I tried it. I started with FormLayout but since I got the same "misalignment" problems with GridLayout, I chose to post the GridLayout version to make it easier to Verify. Please tell me I can get option #2 working without too much trouble or how to make option #3 work.
Below is my MCV example:
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.basic.*;
public class TestFrame3 extends JFrame {
public TestFrame3 () {
JLabel l1 = new JLabel("l1"); l1.setBorder(new EmptyBorder(0, 0, 0, 0));
JLabel r1 = new JLabel("r1"); r1.setBorder(new EmptyBorder(0, 0, 0, 0));
JLabel l2 = new JLabel("l2"); l2.setBorder(new EmptyBorder(0, 0, 0, 0));
JComboBox r2 = new JComboBox(); r2.setBorder(new EmptyBorder(0, 0, 0, 0));
r2.setRenderer(new BasicComboBoxRenderer() {
#Override
public Component getListCellRendererComponent (JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JComponent comp = (JComponent) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
comp.setBorder(new EmptyBorder(0, 0, 0, 0));
return comp;
}
});
JPanel p = new JPanel();
p.setLayout(new GridLayout(2, 2));
p.add(l1);
p.add(r1);
p.add(l2);
p.add(r2);
getContentPane().add(p);
setSize(new Dimension(100, 200));
}
public static void main (String args[]) {
new TestFrame3().setVisible(true);
}
}
Here's what is displayed, showing the 'r' in 'r1' not lined up with the left-most pixels of the border stroke of the JComboBox:
At Sergiy's prompting, I tested the code on Windows 10 and Fedora 20 and was also unable to reproduce the problem. It makes me wonder. Also at his prompting, I tried setting the UI to BasicComboBoxUI instead of using the default com.apple.laf.AquaComboBoxUI and the alignment problem did not manifest. Unfortunately, that UI is unattractive in a different way.

Related

Libgdx- Resetting a Vector3 to use it multiple times in different situations

OK guys I need your help,
I'm trying to figure out how to reset a Vector3, to use it on multiple situations,...
For example I got a code where for testing purpose I have several buttons,
Where the first one uses a Matrix4 that refers to a Vector3 to translate a player,
How would I go to do so:
Button 1 pressed
Vector3: 1,2,3
Button 2 pressed
Vector3: reset, new values 2,4,6
Pseudo code for comprehension..
Can't seem to find a correct way to do so,
Not behind the computer right now,
Code will come in time,
Maybe if else if can do the trick but not sure :3
Any hint?
for reference, edited qn:
stage.addActor(tpS);
ghost = new Matrix4();
tpIleApprentis.addListener((new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
TpS.hide();
translation = new Vector3(86.83f,96f,63.5f);
ghost.getTranslation(translation);
translation.set(0,0,0);
PlayerSystem.characterComponent.ghostObject.setWorldTransform(ghost);
return false;
}
}));
Ok so,
as I was working with Ashley ECS and Bullet System,
I finally ended up using such method that basically remove the player and recreate the player,
Yes the solution isn't optimal, but it works,
Actually it's plenty sufficient:
tpIleApprentis0.addListener(new InputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
gameWorld.remove(gameWorld.character);
gameWorld.remove(gameWorld.characterHair);
gameWorld.remove(gameWorld.characterEar);
gameWorld.remove(gameWorld.characterScar);
gameWorld.remove(gameWorld.characterMouth);
System.out.println("Teleportation Ville des Apprentis");
gameWorld.createPlayer(86.8f,64.4f,-96.6f);
return false;
}
});
Ashley engine is created and located in gameworld class;
remove method is part of ashley ecs system and involves bullet component
for the create method it's the same:
public void remove(Entity entity)
{
engine.removeEntity(entity);
bulletSystem.removeBody(entity);
}
public void createPlayer(float x, float y, float z)
{
character = playerFactory.createMaleCharacter(bulletSystem, x, y, z);
characterHair = playerFactory.createMaleHair(x, y, z);
characterEar = playerFactory.createMaleEar(x, y, z);
characterMouth = playerFactory.createMaleMouth(x, y, z);
characterScar = playerFactory.createMaleScar(x, y, z);
engine.addEntity(character);
engine.addEntity(characterHair);
engine.addEntity(characterEar);
engine.addEntity(characterMouth);
engine.addEntity(characterScar);
...
if anybody got a better solution?
but as said, actually this solution fits my needs
You don't need to "reset" the Vector3 before reusing it, you can simply override it with new values using one of the set methods.
https://libgdx.badlogicgames.com/ci/nightlies/docs/api/com/badlogic/gdx/math/Vector3.html#set-float-float-float-
Vector3 vector = new Vector3(1, 2, 3);
...
vector.set(2, 4, 6); // reuse

How to tween alpha of a BitmapFontCache in libgdx?

I am animating some text in my libgdx application and would like a label text to fade-in and move (e.g. similar to this jsfiddle).
I can move, and change alpha of other objects (e.g. Sprites) and can move BitmapFontCaches. However I can't get alpha of the BitmapFontChage to change.
Declaration:
message = new BitmapFontCache(messageFont, true);
message.setWrappedText("some text", 10.0f, 10.0f, 10.0f);
message.setAlphas(0.0f);
In my screen class, I override the render method, and call .draw() on a renderer class, which is (among other things) essentially just a message.draw(batch); call.
#Override
public void render(float delta) {
...
try{
batch.begin();
feedbackRenderer.draw(batch);
tweenManager.update(delta);}
finally{
batch.end();
}
}
Then as a part of a timeline I call these two Tweens. (yes, they are wrapped in .push( ) and I do start my tweenManager:)
Tween.to(message, BitmapFontCacheAccessor.POSITION_X, animationDuration)
.target(35.0f)
Tween.to(message, BitmapFontCacheAccessor.ALPHA, animationDuration)
.target(1.0f)
The BitmapFontCacheAccessor tries to setAlphas() of the BitmapFontCache as such:
public class BitmapFontCacheAccessor implements TweenAccessor<BitmapFontCache> {
public static final int POSITION_X = 1;
public static final int ALPHA = 2;
#Override
public void setValues(BitmapFontCache target, int tweenType, float[] newValues) {
switch (tweenType) {
case POSITION_X:
float y = target.getY();
target.setPosition(newValues[0], y);
break;
case ALPHA:
target.setAlphas(newValues[0]);
break;}
}...
It moves the label (==> .setPosition(x, y) works!), but does not even touch the alpha. This exact same approach works for Sprites, which fade in nicely.
Is there perhaps some catch when tweening alpha for the BitmapFontCache? Is it possible?
Many thanks!
After a good hour of debugging I have found the reason for this funny behavior.
Libgdx's BitmapFontCache does not have a getAlphas() method
Therefore, to get the alpha channel I used getColor().a
However, these two are not always synced. The behavior is quite random, I myself am not quite sure when it syncs and when it doesn't (f.ex. in the question above, the fade-outs would work, but fade-ins wouldn't)
The solution is to change and declare BOTH alpha channels.
Definition of BitmapFontCache:
message = new BitmapFontCache(messageFont, true);
message.setColor(1,1,1,0);
message.setAlphas(0);
and inside TweenAccessor:
case ALPHA:
//first alpha channel
target.setAlphas(newValues[0]);
//second alpha channel
Color c = target.getColor();
c.a = newValues[0];
target.setColor(c);
break;
To you, hopeless SO wanderer, I address this answer so that you can spend some of the finite number of minutes of your life better than I did.

Setting up w,a,s,d on JScrollPane on a main GUI in small game

I have a Game Window to which I am trying to put W, A, S and D as scroll keys for the JScrollPane. This is what I have done so far on the method that runs it. The JScrollPane is not local. When I run it, the program runs fine but, the keys don't do anything. I tried it with putting a breakpoint inside the action, so that it would run when it was responding to a button push but it didn't do anything.
I would appreciate any input, let me know if you need more information.
/**
* This sets all the key commands to the scroll pane for up, down, left, right.
* These are W, S, A, D
* It also sets the increment amount.
*/
private void setupScrollKeys()
{
//sets up the scroll panes unit increment.
final int increment = 80;
scrollPane.getHorizontalScrollBar().setUnitIncrement(increment);
scrollPane.getVerticalScrollBar().setUnitIncrement(increment);
//set all the keyStrokes for up, down, left, right on the scroll pane.
KeyStroke kUp = KeyStroke.getKeyStroke(KeyEvent.VK_W, 0);
KeyStroke kDown = KeyStroke.getKeyStroke(KeyEvent.VK_S, 0);
KeyStroke kLeft = KeyStroke.getKeyStroke(KeyEvent.VK_A, 0);
KeyStroke kRight = KeyStroke.getKeyStroke(KeyEvent.VK_D, 0);
// set W for key up.
scrollPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
.put(kUp, "keyUp");
scrollPane.getActionMap().put("keyUp", new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
final JScrollBar bar = scrollPane.getVerticalScrollBar();
int currentValue = bar.getValue();
bar.setValue(currentValue - increment);
}
});
}
Try changing the line
scrollPane.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
.put(kUp, "keyUp");
to
scrollPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(kUp, "keyUp");
I had no idea of key bindings, so I found this tutorial really handy.
How to Use Key Bindings

Intersecting JLabels inside a JTable

In the below image I am trying to achieve the following.I have a table and lots of labels embossed over table cells.The height of the labels is always equal to the cell height.So if two labels come in the same point one hides the another as shown in the longer rectangles with red rect over blue.Alternatively what I want is to make the height as half and there by show both the rectangles(showing starting and end points of the rectangle since height is of no use I can half the height of the rectangle to accomodate one more in the same cell.)
I have to do this inside a JTable.To attach a label we can create a JLabel object by setting the rectangular bounds and using table.add(label);
image here
Where did you get the idea that you can do table.add(label) and hope that the label be magically painted over the table?
(Same ??? for #dpatch's answer.)
You have to use cell renderer/editor for any custom painting inside table. (Or layered pane/glass pane if it's something floating above table, but it looks like you want the labels in the cells.)
A crude renderer that paints cell (0, 0) as half-height blue on top of full-height red:
table.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer()
{
private int row_ = 0;
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column)
{
row_ = row;
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
}
public void setUI(LabelUI ui)
{
super.setUI(new BasicLabelUI()
{
public void paint(Graphics g, JComponent c)
{
super.paint(g, c);
if( row_ == 0 )
{
Rectangle r = g.getClipBounds();
g.setColor(Color.RED);
g.fillRect(r.x, r.y, r.width, r.height);
g.setColor(Color.BLUE);
g.fillRect(r.x, r.y + 1, r.width, r.height/2 - 1);
}
}
});
}
});
Check out the following presentation. I think it talks about solution to similar problem
http://developers.sun.com/learning/javaoneonline/2008/pdf/TS-4982.pdf?cid=925395
When you find two labels that need to be in the same cell, create a JPanel with the red and blue labels each taking up half the height of the panel. Then just add the panel to the table.

swing: JSlider but with coarse/fine controls?

I have a JSlider with 65536 different values. It works great for coarse adjustments and for very fine adjustments (+/-1 using up/down arrow) but is very poor in the middle.
Is there anything out there that would be better? I can vaguely imagine taking 2 sliders one for coarse + fine adjustments, but can't really figure out how to get them to work together.
What about using a JSpinner instead of a JSlider? With a SpinnerNumberModel, you can set the step size and even change the step size dynamically.
If you're OK with having multiple controls, you could even have two spinners, one for setting your values and another for setting the step size that is used by the first spinner.
For an example of this, I took the SliderDemo code from the Swing slider tutorial and modified it instead to use two JSpinners instead of a single JSlider. Here's the most interesting part of the code that I changed:
//Create the slider^H^H^H^H^H^H spinners.
// JSlider framesPerSecond = new JSlider(JSlider.HORIZONTAL,
// FPS_MIN, FPS_MAX, FPS_INIT);
final int initStep = 1;
final SpinnerNumberModel animationModel = new SpinnerNumberModel(FPS_INIT,
FPS_MIN,
FPS_MAX,
initStep);
final SpinnerNumberModel stepSizeModel = new SpinnerNumberModel(initStep,
1,
10,
1);
final JSpinner framesSpinner = new JSpinner(animationModel);
framesSpinner.addChangeListener(this);
final JSpinner stepSpinner = new JSpinner(stepSizeModel);
stepSpinner.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent arg0)
{
animationModel.setStepSize(stepSizeModel.getNumber());
}
});
I also had to make a bunch of less interesting changes, such as creating a label for the step size spinner, adding the new label and new spinner to the container, and changing the stateChanged() method on this to cast the source of the event to a JSpinner instead of casting it to a JSlider.
You could, of course, elaborate on this further, such as increasing the step size for the step size spinner (for example, so that you can change the step size from 1 to 101 in a single click). You could also use a different control instead of a JSpinner to set the step size, such as a combo box.
Finally, to make this all really easy to use, you would likely want to hook up some keystroke accelerators (possibly through a menu?) so that you could change the step size without actually moving the mouse or the keyboard focus from one spinner to another.
Edit: Given that you have to use a JSlider no matter what, are you aware that you can use PgUp/PgDn to move up and down by 1/10th of the total range?
If you want to change that 1/10th amount (such as making it dynamic), then you'll need to override the the method BasicSliderUI.scrollByBlock().
Here's an example where I just overrode the UI class of a JSlider to step by 1/4th of the range, instead of 1/10th:
//Create the slider.
JSlider framesPerSecond = new JSlider(JSlider.HORIZONTAL,
FPS_MIN, FPS_MAX, FPS_INIT);
framesPerSecond.setUI(new javax.swing.plaf.metal.MetalSliderUI() {
private static final int SLIDER_FRACTION = 4;
/**
* This code is cut, paste, and modified from
* {#link javax.swing.plaf.basic.BasicSliderUI#scrollByBlock(int).
* I should be ashamed of cutting and pasting, but whoever hardcoded the magic
* number "10" in the original code should be more ashamed than me. ;-)
*
* #param direction
* either +1 or -1
*/
#Override
public void scrollByBlock(final int direction) {
synchronized(slider) {
int oldValue = slider.getValue();
int blockIncrement = (slider.getMaximum() - slider.getMinimum()) / SLIDER_FRACTION;
if (blockIncrement <= 0 && slider.getMaximum() > slider.getMinimum()) {
blockIncrement = 1;
}
int delta = blockIncrement * ((direction > 0) ? POSITIVE_SCROLL : NEGATIVE_SCROLL);
slider.setValue(oldValue + delta);
}
}
});
From here, it wouldn't be too hard to replace that constant SLIDER_FRACTION with a variable that was set by another slider or by a spinner, would it?