问题
I have a drawing canvas with an OnTouchListener
from which I call an AlertDialog
.
In the dialog I reset the underlying data for the canvas (or not depending on user). On returning to the canvas with dialog.cancel()
the canvas does not redraw and I want it to.
This means the user has to click on the canvas to cause it to redraw - not good!
Because the dialog runs asynchronously any call to invalidate()
in the canvas is completed before the dialog returns the changed underlying data. Any attempt I make to invalidate or reference the canvas from inside the dialog buttons code results in errors. I seem to be in catch 22!
Can enyone give me advice?
dialog code:
case DIALOG_NEW_ID:
AlertDialog.Builder builder5 = new AlertDialog.Builder(this);
builder5.setMessage(" WARNING" +
"\nYour current game will be lost")
.setCancelable(false)
.setPositiveButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
})
.setNegativeButton("Continue", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
cells.reset();
gameMode = 0;
dialog.cancel();
}
});
AlertDialog alert5 = builder5.create();
alert5.setOnDismissListener(new DialogInterface.OnDismissListener() {
public void onDismiss( DialogInterface dialog) {
Log.d(TAG, "Dialog cancelled");// debug log entry
//myBoard.invalidate();
}
});
dialog = alert5;
break;
Dialog calling code onTouch
in the canvas:
case MODE_SOLUTION:
break;
default:
showDialog(DIALOG_NEW_ID);
invalidate();
}// end switch
The Main Class set up:
public class SudokuGame extends Activity {
static final int DIALOG_OPEN_ID = 0;
static final int DIALOG_INFO_ID = 1;
static final int DIALOG_FAIL_ID = 2;
static final int DIALOG_SAVE_ID = 3;
static final int DIALOG_NEW_ID = 4;
static final int MODE_ENTRY = 0;
static final int MODE_PLAY = 1;
static final int MODE_SHOW_ERRORS = 3;
static final int MODE_SOLUTION = 4;
final String TAG = "Game";
int gameMode;
SKU cells;
View myBoard;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_LEFT_ICON);
View myBoard = new NewBoard(this);
setContentView(myBoard);
setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, R.drawable.ic_launcher);
showDialog(DIALOG_OPEN_ID);
}// end onCreate
protected Dialog onCreateDialog(int id) {
The Class NewBoard which is nested in the main class:
class NewBoard extends View implements OnTouchListener{
int cW; // canvas width
int cH; // canvas height
int cellSize,textSize;
int boardX,boardY;
int runner, tX, tY,pX,pY,selectorX,selectorY;
int gap ;
int btn1X,btn1Y, selected;
int infoButtonX, infoButtonY,quitButtonX,quitButtonY;
boolean btn1Pressed, btn2Pressed, btn3Pressed, btn4Pressed, btn5Pressed;
String btn1,btn2,btn3,btn4,btn5;
public NewBoard(Context context){ // NewBoard Constructor
super(context);
this.setOnTouchListener(this);
cells = new SKU();
readStateStore();
}// end NewBoard Constructor
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
Rect textRect = new Rect();
回答1:
Two possibilities:
- make the dialog non-cancelable
- set an OnCancelListener for the dialog that will then call invalidate().
回答2:
Could you post some code of your situation with the dialog box and invalidate(), and the error message being returned back?
I don't see why you couldn't do the following (dialog box that invalidates a mapView):
AlertDialog.Builder builderAccountInfo = new AlertDialog.Builder(this);
builderAccountInfo.setMessage("TEST")
.setCancelable(false)
.setTitle("TEST")
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
changeUserCanvas();
mapView.invalidate();
dialog.cancel();
}
});
AlertDialog alertAccountInfo = builderAccountInfo.create();
alertAccountInfo.show();
The error would probably come from the context you're using to invalidate, but more information on the changes to the canvas you're making and your dialog box code is needed.
////////////////////////////////Edit
it looks like there is a problem between the local and global variable of View myBoard.
public class SudokuGame extends Activity {
static final int DIALOG_OPEN_ID = 0;
static final int DIALOG_INFO_ID = 1;
static final int DIALOG_FAIL_ID = 2;
static final int DIALOG_SAVE_ID = 3;
static final int DIALOG_NEW_ID = 4;
static final int MODE_ENTRY = 0;
static final int MODE_PLAY = 1;
static final int MODE_SHOW_ERRORS = 3;
static final int MODE_SOLUTION = 4;
final String TAG = "Game";
int gameMode;
SKU cells;
View myBoard;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_LEFT_ICON);
View myBoard = new NewBoard(this);
setContentView(myBoard);
setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, R.drawable.ic_launcher);
showDialog(DIALOG_OPEN_ID);
}// end onCreate
View myBoard in onCreate is initialized locally, but the global View myBoard has not been initialized because of the local scope. You have two myBoard variables and only one is initialized. To fix this quickly, I would change:
View myBoard = new NewBoard(this);
to
myBoard = new NewBoard(this);
来源:https://stackoverflow.com/questions/4888481/how-to-invalidate-on-return-from-a-dialog