如何从 Canvas 回到 MIDlet

Posted

技术标签:

【中文标题】如何从 Canvas 回到 MIDlet【英文标题】:How to get from Canvas back to MIDlet 【发布时间】:2012-05-16 20:31:50 【问题描述】:

我试图弄清楚,在 Canvas 中的 commandAction 方法中,如何让我的命令按钮带我回到 MIDlet 的开头? (基本上重新开始)。

当按键触发时,我让它带我进入一个新的列表页面。在那个页面上,我有一个后退按钮,理想情况下我需要它来带我回到 CalandarMidlet 页面。我的逻辑是,在 commandAction 方法中我只会从那里调用 startApp() 但这不起作用,因为 commandAction 是静态的,而 startApp() 不是。

我已经用尽了所有的可能性,现在我被难住了。任何指导将不胜感激。

在 commandAction 方法内的 CalendarCanvas 页面中,我注释掉了我卡住的地方。我正在尝试让“后退”按钮带我回到应用程序的开头(回到日历)。

import java.io.IOException;
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

/**
 * @author addylesson
 */
public class CalendarMidlet extends MIDlet 
    private Display mydisplay;
    private Command f,e,l;

    public CalendarMidlet()

    public void startApp() 
        final Displayable d = new CalendarCanvas(this);

        e = new Command("Back", Command.BACK, 0);
        f = new Command("Exit", Command.EXIT, 1);
        l = new Command("List", Command.SCREEN, 3);
        d.addCommand(f);
        d.addCommand(e);
        d.addCommand(l);
        //mList.addCommand(e);
        d.setCommandListener(new CommandListener()
        
            public void commandAction(Command c, Displayable s)
            
                if(c == e)
                    mydisplay.setCurrent(d);
                if(c == l)
                    //mydisplay.setCurrent(mList);
                //else if(c == f)
            notifyDestroyed();
            
         );
        /*mList.setCommandListener(new CommandListener()
        
            public void commandAction(Command c, Displayable s)
            
                if(c == e)
                    mydisplay.setCurrent(d);
                else if(c == f)
            notifyDestroyed();
            
         );*/
        mydisplay = Display.getDisplay(this);
        mydisplay.setCurrent(d);
    

    public void pauseApp() 
    

    public void destroyApp(boolean unconditional) 
    



import java.io.IOException;
import java.util.Date;

import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;

public class CalendarCanvas extends Canvas

    CalendarWidget calendar = null;
    MIDlet midlet = null;
        private Alert alert;
        private List mList;
        private Command f;
        private Display mydisplay;

        String[] stringElements =  "Celeberity", "Sports", "Zodiac" ;
        Image[] imageElements =  loadImage("/airplane.png"),
                              loadImage("/car.png"), loadImage("/hotel.png") ;

    public CalendarCanvas(final MIDlet m)
    

                this.midlet = m;

        calendar = new CalendarWidget(new Date());

        calendar.headerFont = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_LARGE);
        calendar.weekdayFont = Font.getFont(Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_MEDIUM);
        calendar.weekdayBgColor = 0xccccff;
        calendar.weekdayColor = 0x0000ff;
        calendar.headerColor = 0xffffff;

                alert = new Alert("Listen", "On this day "
                        +calendar.getSelectedDate().toString()+ "stuff happened", null, null);
                alert.setTimeout(Alert.FOREVER);
                mList = new List("Reservation type", List.IMPLICIT,
                stringElements, imageElements);
                f = new Command("Back", Command.BACK, 0);
                mList.addCommand(f);
                mList.setCommandListener(new CommandListener()
                      
                      public void commandAction(Command c, Displayable s)
                        
                            if (c == f)
                                //HOW DO I GET BACK TO THE START OF THE MIDLET??


                            if (c == List.SELECT_COMMAND) 
                         int index = mList.getSelectedIndex();
                         Alert alert2 = new Alert("Your selection",
                        "You chose " + mList.getString(index) + ".",
                        null, AlertType.INFO);
                        mydisplay = Display.getDisplay(midlet);
                        mydisplay.setCurrent(alert2);
        

                        
                       );


        calendar.initialize();
    


    protected void keyPressed(int key)
    
        int keyCode = getGameAction(key);
        String day = calendar.getSelectedDate().toString();
        if(keyCode == FIRE)
        
            /*Display.getDisplay(midlet).setCurrent(
                new Alert("Selected date", 
                                calendar.getSelectedDate().toString(), null, 
                                AlertType.CONFIRMATION)
            );*/
                        Display.getDisplay(midlet).setCurrent(mList);
        
        else
        
            calendar.keyPressed(keyCode);

            repaint();
        
    

    protected void paint(Graphics g)
    
        g.setColor(0xffffff);
        g.fillRect(0, 0, getWidth(), getHeight());

        calendar.paint(g);
    
        private Image loadImage(String name) 
        
        Image image = null;
        try 
        image = Image.createImage(name);
        
        catch (IOException ioe) 
        System.out.println(ioe);
        
        return image;
        







import java.util.Calendar;
import java.util.Date;

import javax.microedition.lcdui.*;

public class CalendarWidget

    static final String[] MONTH_LABELS = new String[]
        "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
    ;
    static final String[] WEEKDAY_LABELS = new String[]
        "M", "T", "W", "T", "F", "S", "S"
    ;
    /* starting week day: 0 for monday, 6 for sunday */
    public int startWeekday = 0;

    /* elements padding */
    public int padding = 2;

    /* cells border properties */
    public int borderWidth = 4;
    public int borderColor = 0x000000;

    /* weekday labels properties */
    public Font weekdayFont = Font.getDefaultFont();
    public int weekdayBgColor = 0x0000ff;
    public int weekdayColor = 0xffffff;

    /* header (month-year label) properties */
    public Font headerFont = Font.getDefaultFont();
    public int headerBgColor = 0x0000ff;
    public int headerColor = 0xffffff;

    /* cells properties */
    public Font font = Font.getDefaultFont();
    public int foreColor = 0x000000;
    public int bgColor = 0x9999ff;
    public int selectedBgColor = 0xffff00;
    public int selectedForeColor = 0xff0000;

    /* internal properties */
    int width = 0;
    int height = 0;
    int headerHeight = 0;
    int weekHeight = 0;
    int cellWidth = 0;
    int cellHeight = 0;

    /* internal time properties */
    long currentTimestamp = 0;
    Calendar calendar = null;
    int weeks = 0;

public CalendarWidget(Date date)

    calendar = Calendar.getInstance();

    //we'll see these 2 methods later
    setDate(date);

    initialize();

public Date getSelectedDate()

    return calendar.getTime();

public void setDate(Date d)

    currentTimestamp = d.getTime();

    calendar.setTime(d);

    //weeks number can change, depending on week starting day and month total days
    this.weeks = (int)Math.ceil(((double)getStartWeekday() + getMonthDays()) / 7);

public void setDate(long timestamp)

    setDate(new Date(timestamp));

void initialize()

    //let's initialize calendar size
    this.cellWidth = font.stringWidth("MM") + 3 * padding;
    this.cellHeight = font.getHeight() + 15 * padding;

    this.headerHeight = headerFont.getHeight() + 2 * padding;
    this.weekHeight = weekdayFont.getHeight() + 2 * padding;

    this.width = 7 * (cellWidth + borderWidth) + borderWidth;
    initHeight();

void initHeight()

    this.height = 
        headerHeight + weekHeight + 
        this.weeks * (cellHeight + borderWidth) + borderWidth;

int getMonthDays()

    int month = calendar.get(Calendar.MONTH);

    switch(month)
    
    case 3:
    case 5:
    case 8:
    case 10:
        return 30;
    case 1:
        return calendar.get(Calendar.YEAR) % 4 == 0 && calendar.get(Calendar.YEAR) % 100 != 0 ? 29 : 28;
    default:
        return 31;
    

int getStartWeekday()

    //let's create a new calendar with same month and year, but with day 1
    Calendar c = Calendar.getInstance();

    c.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
    c.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
    c.set(Calendar.DAY_OF_MONTH, 1);

    //we must normalize DAY_OF_WEEK returned value
    return (c.get(Calendar.DAY_OF_WEEK) + 5) % 7;

public void keyPressed(int key)

    switch(key)
    
    case Canvas.UP:
        go(-7);
        break;
    case Canvas.DOWN:
        go(7);
        break;
    case Canvas.RIGHT:
        go(1);
        break;
    case Canvas.LEFT:
        go(-1);
        break;
    

void go(int delta)

    int prevMonth = calendar.get(Calendar.MONTH);

    setDate(currentTimestamp + 86400000 * delta);

    //we have to check if month has changed
    //if yes, we have to recalculate month height
    //since weeks number could be changed
    if(calendar.get(Calendar.MONTH) != prevMonth)
    
        initHeight();
    

public void paint(Graphics g)

    //painting background
    g.setColor(bgColor);
    g.fillRect(0, 0, width, height);

    //painting header (month-year label)
    g.setFont(headerFont);
    g.setColor(headerColor);
    g.drawString(MONTH_LABELS[calendar.get(Calendar.MONTH)] + " " + calendar.get(Calendar.YEAR), width / 2, padding, Graphics.TOP | Graphics.HCENTER);

    //painting week days labels
    g.translate(0, headerHeight);

    g.setColor(weekdayBgColor);
    g.fillRect(0, 0, width, weekHeight);

    g.setColor(weekdayColor);
    g.setFont(weekdayFont);

    for(int i = 0; i < 7; i++)
    
        g.drawString(WEEKDAY_LABELS[(i + startWeekday) % 7],
            borderWidth + i * (cellWidth + borderWidth) + cellWidth / 2,
            padding,
            Graphics.TOP | Graphics.HCENTER
        );
    

    //painting cells borders
    g.translate(0, weekHeight);

    g.setColor(borderColor);

    for(int i = 0; i <= weeks; i++)
    
        g.fillRect(0, i * (cellHeight + borderWidth), width, borderWidth);
    
    for(int i = 0; i <= 7; i++)
    
        g.fillRect(i * (cellWidth + borderWidth), 0, borderWidth, height - headerHeight - weekHeight);
    

    //painting days
    int days = getMonthDays();
    int dayIndex = (getStartWeekday() - this.startWeekday + 7) % 7;

    g.setColor(foreColor);

    int currentDay = calendar.get(Calendar.DAY_OF_MONTH);

    for(int i = 0; i < days; i++)
    
        int weekday = (dayIndex + i) % 7;
        int row = (dayIndex + i) / 7;

        int x = borderWidth + weekday * (cellWidth + borderWidth) + cellWidth / 2;
        int y = borderWidth + row * (cellHeight + borderWidth) + padding;

        //if this is the current day, we'll use selected bg and fore colors
        if(i + 1 == currentDay)
        
            g.setColor(selectedBgColor);
            g.fillRect(
                borderWidth + weekday * (cellWidth + borderWidth), 
                borderWidth + row * (cellHeight + borderWidth), 
                cellWidth, cellHeight);
            g.setColor(selectedForeColor);
        

        g.drawString("" + (i + 1), x, y, Graphics.TOP | Graphics.HCENTER);

        //if this is the current day, we must restore standard fore color 
        if(i + 1 == currentDay)
        
            g.setColor(foreColor);
        
    
    //let's traslate back!
    g.translate(0, - headerHeight - weekHeight);


【问题讨论】:

@gnat 谢谢。我花了更多时间思考我应该把什么作为最后一个标签而不是任何事情哈哈。 【参考方案1】:

直接(坦率地说有点愚蠢)的方法是在你卡住的地方调用m.startApp()。 “愚蠢”的部分是您想要调用的不是 startApp,但是正如您正确所说的“带我回到 CalendarMidlet 页面”。

为了更贴近你的意图,我更喜欢refactorCalendarMidlet...

    // ...
    public void startApp() 
        // extract stuff to start over into dedicated method,
        // keep the rest here
        e = new Command("Back", Command.BACK, 0);
        f = new Command("Exit", Command.EXIT, 1);
        l = new Command("List", Command.SCREEN, 3);
        mydisplay = Display.getDisplay(this);
        startOver();
    

    public void startOver() 
        // encapsulate stuff to start over here
        final Displayable d = new CalendarCanvas(this);

        d.addCommand(f);
        d.addCommand(e);
        d.addCommand(l);
        d.setCommandListener(new CommandListener()
        
            public void commandAction(Command c, Displayable s)
            
                if(c == e)
                    mydisplay.setCurrent(d);
                if(c == l)
                    //mydisplay.setCurrent(mList);
                //else if(c == f)
            notifyDestroyed();
            
         );
        mydisplay.setCurrent(d);
    
    // ...

...然后稍微调整一下CalendarCanvas,以便使用上面“更智能”的设计...

    // ...
    CalendarMidlet midlet = null; // was declared as MIDlet before

    // ...
    public CalendarCanvas(final CalendarMIDlet m) // parameter was MIDlet
    

                this.midlet = m;
                // ...
    

...这样在commandAction 中我可以调用一个方法来做我想做的事,而不仅仅是愚蠢的startApp

 if (c == f)
     m.startOver(); // take me back to the CalendarMidlet page

【讨论】:

哇。我真的很生气自己没有考虑 m.startapp。我完全忘记了 Midlet 是 CalendarCanvas 类中的一个实例。我只有一年半的时间进入java,所以我知道我会变得更好。将尝试重构。再次感谢@gnat。 嘿@gnat,我做了一些更改,只需要解决 2 个问题,就可以全面了解如何构建此日历。我必须发一个全新的帖子吗?或者我可以在添加评论部分发布代码吗? @Addy75 发布新帖子会更安全 - 在 Stack Overflow,回答者往往不喜欢 “chameleon questions”

以上是关于如何从 Canvas 回到 MIDlet的主要内容,如果未能解决你的问题,请参考以下文章

Canvas 绘制星空

Unity3d游戏开发浅谈UGUI中的Canvas以及三种画布渲染模式

canvas API 如何改变画圆起点,为啥老是从3点钟方向开始画,我要画空心圆,从6点钟方向开始画

如何从 canvas.onmousemove 函数外部访问全局变量?

如何从图形 Canvas 类中获取坐标? [复制]

如何从 html2Canvas 调整 DIV 中的画布输出大小?