I have a simple bean:
public class SimpleBean implements Serializable {
String stringMe;
double autoboxMe;
// ... boilerplate ...
}
I have created a view implementing Editor.
public class View extends Component implements Editor<SimpleBean> {
#UiField
HasValue<String> stringMeEditor;
#UiField
HasValue<Double> autoboxMeEditor;
// boilerplate uibinder blabla
}
If I run this editor, either standalone or in a tree, I only receive a value for the string in the view, the double-box stays empty.
If I take the burden to write a LeafValueEditor, explicitely setting the values, in the setValue() method, the doubles appear.
So, where is the issue? Is the SimpleBeanEditorDriver not autobox-able and won't find the matching editor field?
UPDATE: The actual code has been asked for.
This is the actual editor. This editor works only, if the LeafValueEditor is in place. If the LVE is replaced by a simple "Editor", it will not present any value.
I know that there will be an issue with NPE if the value is null, but that can be managed with Validation.
package de.srs.pen.portal.widgets.metadataeditor;
import com.google.gwt.activity.shared.Activity;
import com.google.gwt.editor.client.LeafValueEditor;
import com.google.gwt.user.client.ui.IsWidget;
import de.srs.pen.api.meta.xml.PageClip;
import de.srs.pen.portal.widgets.editors.HasDeleteHandlers;
import de.srs.pen.portal.widgets.utils.HasActivity;
public interface PageClipEditor
extends Activity
{
public interface View
extends IsWidget, HasActivity<PageClipEditor>, LeafValueEditor<PageClip>, HasDeleteHandlers
{
void removeFromParent();
}
}
This is the implementation of the View interface.
package de.srs.pen.portal.widgets.metadataeditor;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.Widget;
import de.srs.pen.api.meta.xml.PageClip;
import de.srs.pen.portal.widgets.editors.EditorDeleteEvent;
import de.srs.pen.portal.widgets.editors.EditorDeleteEventHandler;
public class PageClipEditorView
extends Composite
implements PageClipEditor.View
{
private static PageClipEditorViewUiBinder uiBinder = GWT.create( PageClipEditorViewUiBinder.class );
interface PageClipEditorViewUiBinder
extends UiBinder<Widget, PageClipEditorView>
{}
private PageClipEditor activity;
#UiField
HasClickHandlers btnDelete;
#UiField
#Path("id")
HasValue<String> idEditor;
#UiField
#Path("display")
PageDisplayEnumEditor displayEditor;
#UiField
#Path("xPos")
HasValue<Double> xPosEditor;
#UiField
#Path("yPos")
HasValue<Double> yPosEditor;
#UiField
#Path("height")
HasValue<Double> heightEditor;
#UiField
#Path("width")
HasValue<Double> widthEditor;
public PageClipEditorView() {
initWidget( uiBinder.createAndBindUi( this ) );
}
#Override
public void setActivity(PageClipEditor activity) {
this.activity = activity;
}
#Override
public PageClipEditor getActivity() {
return this.activity;
}
#Override
public HandlerRegistration addDeleteHandler(EditorDeleteEventHandler handler) {
return addHandler( handler, EditorDeleteEvent.TYPE );
}
#UiHandler("btnDelete")
public void handleDelete(ClickEvent ev) {
fireEvent( new EditorDeleteEvent() );
}
#Override
public void setValue(PageClip value) {
displayEditor.asEditor().setValue( value.getDisplay() );
heightEditor.setValue( value.getHeight() );
widthEditor.setValue( value.getWidth() );
xPosEditor.setValue( value.getxPos() );
yPosEditor.setValue( value.getyPos() );
idEditor.setValue( value.getId() );
}
#Override
public PageClip getValue() {
PageClip clip = new PageClip( idEditor.getValue(),
xPosEditor.getValue(), yPosEditor.getValue(),
widthEditor.getValue(), heightEditor.getValue(),
displayEditor.asEditor().getValue() );
return clip;
}
}
This is the uibinder template file.
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:p="urn:import:de.srs.pen.portal.widgets.metadataeditor">
<ui:with type="de.srs.pen.portal.widgets.metadataeditor.MetadataEditorText"
field="res" />
<ui:with type="de.srs.pen.portal.widgets.icons.WidgetIcons"
field="icon" />
<ui:style>
</ui:style>
<g:HTMLPanel>
<g:Image ui:field="btnDelete" resource="{icon.circleCloseDeleteGlyph}"
height="16px" width="16px" title="{res.pageclipDelete}" />
<g:InlineLabel text="{res.pageclipName}" />
<g:TextBox ui:field="idEditor" width="5em"/>
<g:InlineLabel text="{res.pageclipDisplay}" />
<p:PageDisplayEnumEditor ui:field="displayEditor" />
<g:InlineLabel text="{res.pageclipXPos}" />
<g:DoubleBox ui:field="xPosEditor" width="2.5em" />
<g:InlineLabel text="{res.pageclipYPos}" />
<g:DoubleBox ui:field="yPosEditor" width="2.5em" />
<g:InlineLabel text="{res.pageclipHeight}" />
<g:DoubleBox ui:field="heightEditor" width="2.5em" />
<g:InlineLabel text="{res.pageclipWidth}" />
<g:DoubleBox ui:field="widthEditor" width="2.5em" />
</g:HTMLPanel>
</ui:UiBinder>
And finally, this is the PageClip Object itself.
package de.srs.pen.api.meta.xml;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "clip", namespace = "urn:srs.pdx.metadata")
public class PageClip implements Serializable {
/**
*
*/
private static final long serialVersionUID = 5556156665068106790L;
#XmlAttribute(required=true)
protected String id;
#XmlAttribute(name = "xPos", required = true)
protected double xPos;
#XmlAttribute(name = "yPos", required = true)
protected double yPos;
#XmlAttribute(name = "width", required = true)
protected double width;
#XmlAttribute(name = "height", required = true)
protected double height;
#XmlAttribute(name ="display", required = false)
protected String display;
public PageClip() {
}
public PageClip( String id, double xPos, double yPos, double width, double height ) {
super();
this.id = id;
this.xPos = xPos;
this.yPos = yPos;
this.width = width;
this.height = height;
}
public PageClip( String id, double xPos, double yPos, double width, double height, String display ) {
this(id, xPos, yPos, width, height);
this.display = display;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public double getxPos() {
return xPos;
}
public void setxPos(double xPos) {
this.xPos = xPos;
}
public double getyPos() {
return yPos;
}
public void setyPos(double yPos) {
this.yPos = yPos;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public String getDisplay() {
return display;
}
public void setDisplay(String display) {
this.display = display;
}
#Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append( "PageClip [id=" )
.append( id )
.append( ", xPos=" )
.append( xPos )
.append( ", yPos=" )
.append( yPos )
.append( ", width=" )
.append( width )
.append( ", height=" )
.append( height )
.append( ", display=" )
.append( display )
.append( "]" );
return builder.toString();
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((display == null) ? 0 : display.hashCode());
long temp;
temp = Double.doubleToLongBits( height );
result = prime * result + (int)(temp ^ (temp >>> 32));
result = prime * result + ((id == null) ? 0 : id.hashCode());
temp = Double.doubleToLongBits( width );
result = prime * result + (int)(temp ^ (temp >>> 32));
temp = Double.doubleToLongBits( xPos );
result = prime * result + (int)(temp ^ (temp >>> 32));
temp = Double.doubleToLongBits( yPos );
result = prime * result + (int)(temp ^ (temp >>> 32));
return result;
}
#Override
public boolean equals(Object obj) {
if( this == obj ) {
return true;
}
if( obj == null ) {
return false;
}
if( !(obj instanceof PageClip) ) {
return false;
}
PageClip other = (PageClip)obj;
if( display == null ) {
if( other.display != null ) {
return false;
}
}
else if( !display.equals( other.display ) ) {
return false;
}
if( Double.doubleToLongBits( height ) != Double.doubleToLongBits( other.height ) ) {
return false;
}
if( id == null ) {
if( other.id != null ) {
return false;
}
}
else if( !id.equals( other.id ) ) {
return false;
}
if( Double.doubleToLongBits( width ) != Double.doubleToLongBits( other.width ) ) {
return false;
}
if( Double.doubleToLongBits( xPos ) != Double.doubleToLongBits( other.xPos ) ) {
return false;
}
if( Double.doubleToLongBits( yPos ) != Double.doubleToLongBits( other.yPos ) ) {
return false;
}
return true;
}
}
Yes, autoboxing is supported, though you should be very careful that it is actually what you want - if the autoBoxMeEditor.getValue() returns null, there will be a NullPointerException when you call driver.flush().
With that said, HasValue is not an editor, and your 'bean' has no getters and setters - these two facts should mean that none of your editor should work, instead of only the string. If you update the question with the real code, I will check back later.
From your edit:
This is the actual editor. This editor works only, if the LeafValueEditor is in place. If the LVE is replaced by a simple "Editor", it will not present any value.
This is the problem, and this is why it appears to work without actually saying that your subeditors are Editors:
#Override
public void setValue(PageClip value) {
displayEditor.asEditor().setValue( value.getDisplay() );
heightEditor.setValue( value.getHeight() );
widthEditor.setValue( value.getWidth() );
xPosEditor.setValue( value.getxPos() );
yPosEditor.setValue( value.getyPos() );
idEditor.setValue( value.getId() );
}
You should not have to write that method, but since a) you are not referring to your editors as Editors, and b) you are making the parent a LeafValueEditor, you must.
First, what does LeafValueEditor mean? In short, your type is saying "I represent some leaf in the editing tree - do not bother to look at my children (i.e. fields) to figure out how to bind sub-editors'. If you had instead actually implemented Editor<PageClip>, the editor system would have looked at the class, and tried to find any editor fields.
Next, since you don't have any editor fields, moving to Editor doesn't help! Instead of referring to your fields as HasValue, refer to them by their real type. This includes the interface LeafValueEditor (remember this from above?), so the String and the double will be bound correctly.
One possible future issue you are going to hit, since you didn't share the code of the driver setup: Make certain that you reference the editor implementation in the driver declaration, not the view interface. You must do this so that the driver knows which impl it is talking to, and what sub-fields (and such, sub-editors) it is expected to have.
Related
There is a method
addHeaderView
Several headers can be added and I can get counter of them, but I do not see how can I get the view back. There is no method getHeaderView(int index), did I miss something?
My answer could be cache the view in ListView tag but maybe you can give me something more obvious.
No exists a native implementation for it but you can use the adapter to manipulate the header as describe these links:
Section header listview
Listview with section header
public class MyBaseAdapter extends BaseAdapter {
public class PojoHeader {}
public class PojoView {}
private final int TYPE_HEADER = 0;
private final int TYPE_VIEW = 0;
private final int VIEW_TYPE_COUNT = 2;
List<Object> mList;
#Override
public int getCount() {
return this.mList.size();
}
#Override
public Object getItem( final int position ) {
return this.mList.get( position );
}
#Override
public long getItemId( final int position ) {
return position;
}
#Override
public int getItemViewType( final int position ) {
if ( this.mList.get( position ) instanceof PojoHeader ) {
return this.TYPE_HEADER;
}
else if ( this.mList.get( position ) instanceof PojoHeader ) {
return this.TYPE_VIEW;
}
return super.getItemViewType( position );
}
#Override
public View getView( final int position, final View convertView, final ViewGroup parent ) {
// Your view
return null;
}
#Override
public int getViewTypeCount() {
return this.VIEW_TYPE_COUNT;
}
#Override
public boolean isEnabled( final int position ) {
if ( this.mList.get( position ) instanceof PojoHeader ) {
return false;
}
else if ( this.mList.get( position ) instanceof PojoHeader ) {
return true;
}
return true;
}
}
I have created a custom android seek bar from lukehorvat tutorial
and added to my preference xml file as below
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto" >
<PreferenceCategory
android:title="Color RGB channels"
android:order="100">
<com.heroku.android.SeekBarDialogPreference
android:defaultValue="20"
android:id="#+id/redchannel"
android:key="redchannel"
android:dialogMessage="Please select red channel:"
android:max="50"
android:title="Red channel"
custom:progressTextSuffix="%"
custom:min="1" />
<com.heroku.android.SeekBarDialogPreference
android:defaultValue="20"
android:dialogMessage="Please select green channel:"
android:max="50"
android:title="Select green channel"
custom:progressTextSuffix="%"
custom:min="1" />
<com.heroku.android.SeekBarDialogPreference
android:defaultValue="20"
android:dialogMessage="Please select blue channel:"
android:max="50"
android:title="Select blue channel"
custom:progressTextSuffix="%"
custom:min="1" />
</PreferenceCategory>
</PreferenceScreen>
And I have added to my preference activity these three seekbars as below
package com.heroku.android;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.view.View;
import android.widget.SeekBar;
public class Preferences extends PreferenceActivity
implements SharedPreferences.OnSharedPreferenceChangeListener {
#Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(com.yuldashev.android.R.xml.preferences);
getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(
this);
}
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onDestroy() {
getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(
this);
super.onDestroy();
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
}
}
The problem is all of them refers to the same seekbardialog custom class and I cannot get the values for these three seekbars seperately. I have tried to seperate them by entitling #+id in xml file but it does not works for me by findviewbyID because the custom SeekBardialogPreference does not support such an option. For example if you adding and single SeekBar by id you do
SeekBar seek1=(SeekBar)findviewByID(resource)
and you get the progress value from seek1 object.
Is there any suggestion how to do the same with custom seekbardialog below
package com.heroku.android;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
/**
* A {#link DialogPreference} that provides a user with the means to select an integer from a {#link SeekBar}, and persist it.
*
* #author lukehorvat
*
*/
public class SeekBarDialogPreference extends DialogPreference
{
private static final int DEFAULT_MIN_PROGRESS = 0;
private static final int DEFAULT_MAX_PROGRESS = 100;
private static final int DEFAULT_PROGRESS = 0;
private int mMinProgress;
private int mMaxProgress;
private int mProgress;
private CharSequence mProgressTextSuffix;
private TextView mProgressText;
private SeekBar mSeekBar;
public SeekBarDialogPreference(Context context)
{
this(context, null);
}
public SeekBarDialogPreference(Context context, AttributeSet attrs)
{
super(context, attrs);
// get attributes specified in XML
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, com.yuldashev.android.R.styleable.SeekBarDialogPreference, 0, 0);
try
{
setMinProgress(a.getInteger(com.yuldashev.android.R.styleable.SeekBarDialogPreference_min, DEFAULT_MIN_PROGRESS));
setMaxProgress(a.getInteger(com.yuldashev.android.R.styleable.SeekBarDialogPreference_android_max, DEFAULT_MAX_PROGRESS));
setProgressTextSuffix(a.getString(com.yuldashev.android.R.styleable.SeekBarDialogPreference_progressTextSuffix));
}
finally
{
a.recycle();
}
// set layout
setDialogLayoutResource(com.yuldashev.android.R.layout.preference_seek_bar_dialog);
setPositiveButtonText(android.R.string.ok);
setNegativeButtonText(android.R.string.cancel);
setDialogIcon(null);
}
#Override
protected void onSetInitialValue(boolean restore, Object defaultValue)
{
setProgress(restore ? getPersistedInt(DEFAULT_PROGRESS) : (Integer) defaultValue);
}
#Override
protected Object onGetDefaultValue(TypedArray a, int index)
{
return a.getInt(index, DEFAULT_PROGRESS);
}
#Override
protected void onBindDialogView(View view)
{
super.onBindDialogView(view);
TextView dialogMessageText = (TextView) view.findViewById(com.yuldashev.android.R.id.text_dialog_message);
dialogMessageText.setText(getDialogMessage());
mProgressText = (TextView) view.findViewById(com.yuldashev.android.R.id.text_progress);
mSeekBar = (SeekBar) view.findViewById(com.yuldashev.android.R.id.seek_bar);
mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener()
{
#Override
public void onStopTrackingTouch(SeekBar seekBar)
{
}
#Override
public void onStartTrackingTouch(SeekBar seekBar)
{
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
// update text that displays the current SeekBar progress value
// note: this does not persist the progress value. that is only ever done in setProgress()
String progressStr = String.valueOf(progress + mMinProgress);
mProgressText.setText(mProgressTextSuffix == null ? progressStr : progressStr.concat(mProgressTextSuffix.toString()));
}
});
mSeekBar.setMax(mMaxProgress - mMinProgress);
mSeekBar.setProgress(mProgress - mMinProgress);
}
public int getMinProgress()
{
return mMinProgress;
}
public void setMinProgress(int minProgress)
{
mMinProgress = minProgress;
setProgress(Math.max(mProgress, mMinProgress));
}
public int getMaxProgress()
{
return mMaxProgress;
}
public void setMaxProgress(int maxProgress)
{
mMaxProgress = maxProgress;
setProgress(Math.min(mProgress, mMaxProgress));
}
public int getProgress()
{
return mProgress;
}
public void setProgress(int progress)
{
progress = Math.max(Math.min(progress, mMaxProgress), mMinProgress);
if (progress != mProgress)
{
mProgress = progress;
persistInt(progress);
notifyChanged();
}
}
public CharSequence getProgressTextSuffix()
{
return mProgressTextSuffix;
}
public void setProgressTextSuffix(CharSequence progressTextSuffix)
{
mProgressTextSuffix = progressTextSuffix;
}
#Override
protected void onDialogClosed(boolean positiveResult)
{
super.onDialogClosed(positiveResult);
// when the user selects "OK", persist the new value
if (positiveResult)
{
int seekBarProgress = mSeekBar.getProgress() + mMinProgress;
if (callChangeListener(seekBarProgress))
{
setProgress(seekBarProgress);
}
}
}
#Override
protected Parcelable onSaveInstanceState()
{
// save the instance state so that it will survive screen orientation changes and other events that may temporarily destroy it
final Parcelable superState = super.onSaveInstanceState();
// set the state's value with the class member that holds current setting value
final SavedState myState = new SavedState(superState);
myState.minProgress = getMinProgress();
myState.maxProgress = getMaxProgress();
myState.progress = getProgress();
return myState;
}
#Override
protected void onRestoreInstanceState(Parcelable state)
{
// check whether we saved the state in onSaveInstanceState()
if (state == null || !state.getClass().equals(SavedState.class))
{
// didn't save the state, so call superclass
super.onRestoreInstanceState(state);
return;
}
// restore the state
SavedState myState = (SavedState) state;
setMinProgress(myState.minProgress);
setMaxProgress(myState.maxProgress);
setProgress(myState.progress);
super.onRestoreInstanceState(myState.getSuperState());
}
private static class SavedState extends BaseSavedState
{
int minProgress;
int maxProgress;
int progress;
public SavedState(Parcelable superState)
{
super(superState);
}
public SavedState(Parcel source)
{
super(source);
minProgress = source.readInt();
maxProgress = source.readInt();
progress = source.readInt();
}
#Override
public void writeToParcel(Parcel dest, int flags)
{
super.writeToParcel(dest, flags);
dest.writeInt(minProgress);
dest.writeInt(maxProgress);
dest.writeInt(progress);
}
#SuppressWarnings("unused")
public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>()
{
#Override
public SavedState createFromParcel(Parcel in)
{
return new SavedState(in);
}
#Override
public SavedState[] newArray(int size)
{
return new SavedState[size];
}
};
}
}
Thank you all!
I'm trying to make a game, using slick2d, and lwjgl. I don't get why this code doesn't work
firstStage.java
package net.CharlesDickenson;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;
public class firstStage extends BasicGameState {
public bossVar bossChecker() {
if(isBeforeMiddleBoss) return bossVar.beforeBoss;
if(isMiddleBoss) return bossVar.Middle;
if(isBeforeBoss) return bossVar.beforeBoss;
if(isBoss) return bossVar.Boss;
return null;
}
#SuppressWarnings("static-access")
public firstStage(int state) {
this.state = state;
}
#Override
public void init(GameContainer _arg0, StateBasedGame _arg1)
throws SlickException {
scoreBoard = new Image("res/scoreBoard.png");
backs = new Image("res/1stageBack.gif");
isBeforeMiddleBoss = true;
isMiddleBoss = false;
isBeforeBoss = false;
isBoss = false;
_arg0.setShowFPS(false);
}
#Override
public void render(GameContainer arg0, StateBasedGame _arg1, Graphics _g)
throws SlickException {
this._g = _g;
new Mob().getGraphics(_g);//i passed graphics
new Char().getGraphics(_g);//i passed graphics
new Bullet().getGraphics(_g);//i passed graphics
_g.drawImage(scoreBoard, 550, 5);
_g.drawImage(backs, 10, 10);
_g.drawString(fps, 580, 570);
_g.drawString("High Score-> Not avaiable", 560, 60);
_g.drawString("Score-> " + currScore, 595, 80);
}
#Override
public void update(GameContainer _arg0, StateBasedGame _arg1, int arg2)
throws SlickException {
fps = "Frame Per Second-> " + _arg0.getFPS();
bossVar b = bossChecker();
switch(b) {
case beforeMiddle :
break;
case Boss :
break;
default:
break;
}
}
#SuppressWarnings("static-access")
#Override
public int getID() {
return this.state;
}
private static int state;
private static int currScore = 0;
private static final int originX = 270;
private static final int originY = 490;
public static int X = originX;
public static int Y = originY;
private static String fps;
private Image scoreBoard;
private Image backs;
private Graphics _g;
public boolean isBeforeMiddleBoss;
public boolean isMiddleBoss;
public boolean isBeforeBoss;
public boolean isBoss;
}
Char.java
package net.CharlesDickenson;
import org.lwjgl.input.Keyboard;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
public class Char extends Bullet implements Entity {
#Override
public void getGraphics(Graphics _g) {
this._g = _g;//so i got graphics, but
if(!isInit) return;
_g.drawImage(Char, getCharX(), getCharY());//this codes doesn't works.
}
#Override
public int getCharX() {
switch(VarTracker.stage) {
case 1:
return firstStage.X;
}
return 0;
}
#Override
public int getCharY() {
switch(VarTracker.stage) {
case 1:
return firstStage.Y;
}
return 0;
}
public void setCharX(int i) {
System.out.println("asdgagsd");
switch(VarTracker.stage) {
case 1:
firstStage.X += i;
}
}
public void setCharY(int i) {
System.out.println("asdgagsd");
switch(VarTracker.stage) {
case 1:
firstStage.Y += i;
}
}
#Override
public void update() {
if(!isInit) return;
_g.drawImage(Char, getCharX(), getCharY());//this code doesn't work, too.
up = Keyboard.isKeyDown(Keyboard.KEY_UP);
down = Keyboard.isKeyDown(Keyboard.KEY_DOWN);
left = Keyboard.isKeyDown(Keyboard.KEY_LEFT);
right = Keyboard.isKeyDown(Keyboard.KEY_RIGHT);
shift = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT);
z = Keyboard.isKeyDown(Keyboard.KEY_Z);
if(up && !shift) {
setCharY(6);
}
if(down && !shift) {
setCharY(-6);
}
if(left && !shift) {
setCharX(-6);
}
if(right && !shift) {
setCharX(6);
}
if(up && shift) {
setCharY(2);
}
if(down && shift) {
setCharY(-2);
}
if(left && shift) {
setCharX(-2);
}
if(right && shift) {
setCharX(2);
}
if(z) {
new Bullet().isFiring = true;
}
if(!z) {
new Bullet().isFiring = false;
}
}
#Override
public void init() {
System.out.println("<Char> Initializing...");
isInit = false;
try {
Char = new Image("res/char.png");
} catch (SlickException e) {
e.printStackTrace();
}
isInit = true;
System.out.println("<Char> Done with init()");
}
private boolean up;
private boolean down;
private boolean left;
private boolean right;
private boolean shift;
private boolean z;
private boolean isInit;
private Image Char;
private Graphics _g;
}
I passed graphics to other class using getGraphics method, to put a image, but it doesn't work.
at render method, it worked, but I can't put a image in other class.
The reason that it doesn't work is that you are using Graphics incorrectly. When Slick2d draws something, it uses the render method. This method is passed an instance of Graphics, to which you can draw stuff. When the call ends the Graphics object is no longer useful for anything. There is thus no reason to pass it to anything that doesn't use it immediately.
What you want to do is create a render method in your Mob, Char and Bullet classes. Make instances of said classes outside of the render method, for instance in init and store them in some data structure, for instance a List. In the render method, you simple traverse the list and call render or draw on each element. A quick example:
// Give the Entity interface two methods if they don't exist already:
public interface Entity {
void render(Graphics g);
void update(int delta);
}
// In firststage.java
List<Entity> list;
// In the init() method
public void init(GameContainer container, StateBasedGame game)
throws SlickException {
...
list = new ArrayList<Entity>();
list.add(new Mob());
list.add(new Char());
list.add(new Bullet());
}
// In the render method
public void render(GameContainer container, StateBasedGame game, Graphics g)
throws SlickException {
...
for (Entity e : list) {
e.draw(g);
}
}
// In the update method
public void update(GameContainer container, StateBasedGame game, int delta)
throws SlickException {
...
for (Entity e : list) {
e.update(delta);
}
}
TL;DR version: The Graphics object exists only to be drawn to in a single render call.
Render is called many times a second, so object creation in that method is not recommended.
Object oriented programming is good at modeling objects. Games tend to model a lot of objects. Make use of it.
I'm following Goolge's example on how to add ListBoxes/SelectionCells to a CellTable, but I can't figure how to change the behaviour so the matching is done not with the string value displayed.
The items I display #SelectionCell are not unique (i.e there can be 2 elements with the same name), so I need to use other fields associated with the object to know which one was selected
for (IrrigationProgramDTO program: programOptions)
categoryNames.add(program.getName());
SelectionCell categoryCell = new SelectionCell(categoryNames);
Column<IrrigationGapDTO, String> categoryColumn = new Column<IrrigationGapDTO, String> (categoryCell) {
#Override
public String getValue(IrrigationGapDTO object) {
if (object.getProgramSelected()!=null)
return object.getProgramSelected().getName();
else
return "";
}
};
categoryColumn.setFieldUpdater(new FieldUpdater<IrrigationGapDTO, String>() {
public void update(int index, IrrigationGapDTO object, String value) {
for (IrrigationProgramDTO program: programOptions) {
//not valid as there could be more than 1 program with the same name
if (program.getName().equals(value)) {
object.setProgramSelected(program);
break;
}
}
}
Here is my new implementation of solution #3 (note that you must add a FieldUpdater to the column for it to work):
import java.util.Arrays;
import java.util.List;
import com.google.gwt.cell.client.AbstractEditableCell;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.BrowserEvents;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.SelectElement;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.client.SafeHtmlTemplates.Template;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
/**
* A {#link Cell} used to render a drop-down list.
*
* #author Gaspard van Koningsveld
*/
public class ItemSelectionCell<C> extends AbstractEditableCell<C, C> {
interface Template extends SafeHtmlTemplates {
#Template("<select tabindex=\"-1\" style=\"width:100%\">")
SafeHtml beginSelect();
#Template("<option value=\"{0}\">{1}</option>")
SafeHtml deselected(int hash, String option);
#Template("<option value=\"{0}\" selected=\"selected\">{1}</option>")
SafeHtml selected(int hash, String option);
#Template("</select>")
SafeHtml endSelect();
}
private static Template template;
private List<C> items;
public ItemSelectionCell(C itemsArray[]) {
this(Arrays.asList(itemsArray));
}
public ItemSelectionCell(List<C> items) {
super(BrowserEvents.CHANGE);
if (template == null) {
template = GWT.create(Template.class);
}
this.items = items;
}
#Override
public void onBrowserEvent(Context context, Element parent, C value, NativeEvent event, ValueUpdater<C> valueUpdater) {
super.onBrowserEvent(context, parent, value, event, valueUpdater);
if (BrowserEvents.CHANGE.equals(event.getType())) {
SelectElement select = parent.getFirstChild().cast();
int newIndex = select.getSelectedIndex();
valueUpdater.update(items.get(newIndex));
}
}
#Override
public void render(Context context, C value, SafeHtmlBuilder sb) {
sb.append(template.beginSelect());
for (int i = 0; i < items.size(); i++) {
C item = items.get(i);
if (item.equals(value)) {
sb.append(template.selected(i, getItemDisplayString(item)));
} else {
sb.append(template.deselected(i, getItemDisplayString(item)));
}
}
sb.append(template.endSelect());
}
public String getItemDisplayString(C item) {
return item.toString();
}
public List<C> getItems() {
return items;
}
public void setItems(List<C> items) {
this.items = items;
}
#Override
public boolean isEditing(Context context, Element parent, C value) {
return false;
}
}
3 possible solutions:
1. Dirty workaround:
Instead of getName() return getName() + some unique identifier:
public String getValue(IrrigationGapDTO object) {
if (object.getProgramSelected()!=null)
return object.getProgramSelected().getName()+"_"+object.getUniqueIdentiufier();
else
return "";
}
then in the FieldUpdater you can split on the "_" character and deal with duplicates
2. Use a unique id instead of getName():
Just generate/assign a unique id to your programms and use it instead of name.
3. Use IrrigationProgramDTO type instead of String:
Instead of String you can use IrrigationProgramDTO class in the Column definition. However you probably have to use a user-defined SelectionCell which takes IrrigationProgramDTO type instead of String as Data-type.
Column<IrrigationGapDTO, IrrigationProgramDTO> categoryColumn = new Column<IrrigationGapDTO, IrrigationProgramDTO> (categoryCell) {
#Override
public IrrigationProgramDTO (IrrigationGapDTO object) {
if (object.getProgramSelected()!=null)
return object.getProgramSelected();
else
return null;
}
};
categoryColumn.setFieldUpdater(new FieldUpdater<IrrigationGapDTO, IrrigationProgramDTO>() {
public void update(int index, IrrigationGapDTO object, IrrigationProgramDTO value) {
object.setProgramSelected(program);
}
}
Here is my implementation of Solution #3 of #Ümit:
public static abstract class EditSelectColumn<E, S> {
Map<String, S> selectionMap = new HashMap<String, S>();
EditColumn<E> column;
protected final String relationshipFieldName;
public EditSelectColumn(String relationshipFieldName) {
this.relationshipFieldName = relationshipFieldName;
for (S option : getOptions()) {
assert getOptionString(option) != null : "Option string cannot be null, please check your database";
selectionMap.put(getOptionString(option), option);
}
SelectionCell cell = new SelectionCell(new ArrayList<String>(selectionMap.keySet()));
column = new EditColumn<E>(cell) {
#Override
public String getValue(E object) {
if (getOption(object) == null)
return "";
return getOptionString(getOption(object));
}
#Override
public void setValue(E object, String value) {
setOption(object, selectionMap.get(value));
}
};
}
public EditColumn<E> getColumn() {
return column;
}
public abstract List<S> getOptions();
public abstract String getOptionString(S option);
public abstract S getOption(E object);
public abstract void setOption(E object, S value);
}
I'm using GWT 2.4. I have a TabLayoutPanel to which I add tabs. Each tab contains a ScrollPanel. My question is, how do I make the tabs in the tab bar wrap to the next line if the width of the tab bar exceeds the visible width?
Thanks, - Dave
GWT's TabLayoutPanel intentionally never wraps tabs. See lines 246-248 in TabLayoutPanel.java - (line 217 defines private static final int BIG_ENOUGH_TO_NOT_WRAP = 16384). You might be able to override this, but as #milan says, it's probably not good design.
Having multiple lines is, indeed, not recommended...
However, to be able to navigate left/right on a single tab bar with many tabs, you can use this recipe:
http://devnotesblog.wordpress.com/2010/06/17/scrollable-gwt-tablayoutpanel/
And an updated implementation that doesn't use the deprecated DeferredCommand:
package whatever.you.want;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.LayoutPanel;
import com.google.gwt.user.client.ui.TabLayoutPanel;
import com.google.gwt.user.client.ui.Widget;
/**
* A {#link TabLayoutPanel} that shows scroll buttons if necessary
*/
public class ScrolledTabLayoutPanel extends TabLayoutPanel {
private static final int IMAGE_PADDING_PIXELS = 4;
private LayoutPanel panel;
private FlowPanel tabBar;
private Image scrollLeftButton;
private Image scrollRightButton;
private HandlerRegistration windowResizeHandler;
private ImageResource leftArrowImage;
private ImageResource rightArrowImage;
public ScrolledTabLayoutPanel(double barHeight, Unit barUnit,
ImageResource leftArrowImage, ImageResource rightArrowImage) {
super(barHeight, barUnit);
this.leftArrowImage = leftArrowImage;
this.rightArrowImage = rightArrowImage;
// The main widget wrapped by this composite, which is a LayoutPanel with the tab bar & the tab content
panel = (LayoutPanel) getWidget();
// Find the tab bar, which is the first flow panel in the LayoutPanel
for (int i = 0; i < panel.getWidgetCount(); ++i) {
Widget widget = panel.getWidget(i);
if (widget instanceof FlowPanel) {
tabBar = (FlowPanel) widget;
break; // tab bar found
}
}
initScrollButtons();
}
#Override
public void add(Widget child, Widget tab) {
super.add(child, tab);
checkIfScrollButtonsNecessary();
}
#Override
public boolean remove(Widget w) {
boolean b = super.remove(w);
checkIfScrollButtonsNecessary();
return b;
}
#Override
protected void onLoad() {
super.onLoad();
if (windowResizeHandler == null) {
windowResizeHandler = Window.addResizeHandler(new ResizeHandler() {
#Override
public void onResize(ResizeEvent event) {
checkIfScrollButtonsNecessary();
}
});
}
}
#Override
protected void onUnload() {
super.onUnload();
if (windowResizeHandler != null) {
windowResizeHandler.removeHandler();
windowResizeHandler = null;
}
}
private ClickHandler createScrollClickHandler(final int diff) {
return new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
Widget lastTab = getLastTab();
if (lastTab == null)
return;
int newLeft = parsePosition(tabBar.getElement().getStyle().getLeft()) + diff;
int rightOfLastTab = getRightOfWidget(lastTab);
// Prevent scrolling the last tab too far away form the right border,
// or the first tab further than the left border position
if (newLeft <= 0 && (getTabBarWidth() - newLeft < (rightOfLastTab + 20))) {
scrollTo(newLeft);
}
}
};
}
/** Create and attach the scroll button images with a click handler */
private void initScrollButtons() {
scrollLeftButton = new Image(leftArrowImage);
int leftImageWidth = scrollLeftButton.getWidth();
panel.insert(scrollLeftButton, 0);
panel.setWidgetLeftWidth(scrollLeftButton, 0, Unit.PX, leftImageWidth, Unit.PX);
panel.setWidgetTopHeight(scrollLeftButton, 0, Unit.PX, scrollLeftButton.getWidth(), Unit.PX);
scrollLeftButton.addClickHandler(createScrollClickHandler(+20));
scrollLeftButton.setVisible(false);
scrollRightButton = new Image(rightArrowImage);
panel.insert(scrollRightButton, 0);
panel.setWidgetLeftWidth(scrollRightButton, leftImageWidth + IMAGE_PADDING_PIXELS, Unit.PX, scrollRightButton.getWidth(), Unit.PX);
panel.setWidgetTopHeight(scrollRightButton, 0, Unit.PX, scrollRightButton.getHeight(), Unit.PX);
scrollRightButton.addClickHandler(createScrollClickHandler(-20));
scrollRightButton.setVisible(false);
}
private void checkIfScrollButtonsNecessary() {
// Defer size calculations until sizes are available, when calculating immediately after
// add(), all size methods return zero
Scheduler.get().scheduleDeferred( new Scheduler.ScheduledCommand() {
#Override
public void execute() {
boolean isScrolling = isScrollingNecessary();
// When the scroll buttons are being hidden, reset the scroll position to zero to
// make sure no tabs are still out of sight
if (scrollRightButton.isVisible() && !isScrolling) {
resetScrollPosition();
}
scrollRightButton.setVisible(isScrolling);
scrollLeftButton.setVisible(isScrolling);
}
}
);
}
private void resetScrollPosition() {
scrollTo(0);
}
private void scrollTo(int pos) {
tabBar.getElement().getStyle().setLeft(pos, Unit.PX);
}
private boolean isScrollingNecessary() {
Widget lastTab = getLastTab();
if (lastTab == null)
return false;
return getRightOfWidget(lastTab) > getTabBarWidth();
}
private int getRightOfWidget(Widget widget) {
return widget.getElement().getOffsetLeft() + widget.getElement().getOffsetWidth();
}
private int getTabBarWidth() {
return tabBar.getElement().getParentElement().getClientWidth();
}
private Widget getLastTab() {
if (tabBar.getWidgetCount() == 0)
return null;
return tabBar.getWidget(tabBar.getWidgetCount() - 1);
}
private static int parsePosition(String positionString) {
int position;
try {
for (int i = 0; i < positionString.length(); i++) {
char c = positionString.charAt(i);
if (c != '-' && !(c >= '0' && c <= '9')) {
positionString = positionString.substring(0, i);
}
}
position = Integer.parseInt(positionString);
} catch (NumberFormatException ex) {
position = 0;
}
return position;
}
}