《交互式程序设计 第2版》一3.5 捕获简单用户交互行为
本節(jié)書摘來華章計(jì)算機(jī)《交互式程序設(shè)計(jì) 第2版》一書中的第3章 ,第3.5節(jié),Joshua Noble 著 毛順兵 張婷婷 陳宇 沈鑫 任燦江 譯更多章節(jié)內(nèi)容可以訪問云棲社區(qū)“華章計(jì)算機(jī)”公眾號(hào)查看。
3.5 捕獲簡單用戶交互行為
從頭開始說起吧。最基本的用戶交互模式有兩種:鼠標(biāo)和鍵盤。下面介紹Processing是如何處理這兩種交互的。要捕獲這兩種交互,你需要知道鼠標(biāo)何時(shí)移動(dòng),鼠標(biāo)按鍵何時(shí)按下,鼠標(biāo)何時(shí)拖動(dòng)(即按住按鍵不放并移動(dòng)鼠標(biāo)),是否有鍵盤按鍵被按下,如果有的話,被按下的是哪個(gè)鍵。與這些相關(guān)的方法和變量是現(xiàn)成的,就存在于Processing應(yīng)用程序中。你只需要使用它們,也就是說,你只需要告訴Processing系統(tǒng),當(dāng)某個(gè)方法被調(diào)用時(shí)你想做什么事情,或者當(dāng)方法被調(diào)用或在draw()方法中時(shí)你想訪問什么變量。
3.5.1 變量mouseX和mouseY
內(nèi)置變量mouseX和mouseY是鼠標(biāo)當(dāng)前位置坐標(biāo),單位是像素。如果鼠標(biāo)在窗口客戶區(qū)的左上角,那么mouseX和mouseY都是0。如果鼠標(biāo)在窗口右下角,并且窗口大小是300像素×300像素,那么mouseX和mouseY都是299。通過這兩個(gè)內(nèi)置變量,你任何時(shí)候都可以獲得鼠標(biāo)位置。示例3-9中,每次draw()被調(diào)用,都輸出鼠標(biāo)位置。
示例3-9:fonts.pde
從代碼注釋可以看出,該程序不僅使用到鼠標(biāo)位置,而且用text()方法將鼠標(biāo)位置作為文本輸出到屏幕上鼠標(biāo)處。這里用到了text()方法,它有3個(gè)參數(shù):
void text(string message, xPosition, yPosition);第一個(gè)參數(shù)是字符串,第二個(gè)和第三個(gè)參數(shù)是字符串顯示位置,它們可以是float型或int型。在前面的例子中,字符串位置被設(shè)置為鼠標(biāo)位置,即變量mouseX和mouseY。
3.5.2 mousePressed()方法
Processing應(yīng)用程序有一個(gè)方法叫mousePressed()。如果應(yīng)用程序獲得焦點(diǎn),那么每當(dāng)用戶按下鼠標(biāo)上任何按鍵,就會(huì)執(zhí)行該回調(diào)方法。當(dāng)然,前面說過,如果沒有draw()方法,那么mousePressed()方法是不會(huì)執(zhí)行的。
示例3-10用幾個(gè)繪圖方法演示了如何使用mousePressed()方法。
示例3-10:mpressed.pde
用戶按下鼠標(biāo)的某個(gè)鍵時(shí),mousePressed()方法執(zhí)行,它將設(shè)置填充色的alpha值設(shè)置為鼠標(biāo)x坐標(biāo)。draw()被不斷調(diào)用,它用修改后的alpha值構(gòu)造填充色,畫出的矩形的填充色也就發(fā)生了改變。
3.5.3 mouseReleased()和mouseDragged()方法
當(dāng)用戶放開鼠標(biāo)按鍵,mouseReleased()方法會(huì)被執(zhí)行。和mousePressed()類似,你可以在mouseReleased()方法中放置一些代碼,以便在鼠標(biāo)按鍵放開時(shí)執(zhí)行。mouseDragged()方法也如此,但它是在用戶拖動(dòng)鼠標(biāo)(按住鼠標(biāo)按鍵并移動(dòng)鼠標(biāo))時(shí)被調(diào)用的。在鼠標(biāo)驅(qū)動(dòng)的應(yīng)用程序中,常常在mouseDragged()方法中將一個(gè)布爾型變量設(shè)置為真,以表示正在拖動(dòng)鼠標(biāo)。示例3-11中,在mouseDragged()方法中放置了繪圖代碼。
示例3-11:dragged.pde
這是一個(gè)簡單的繪圖程序。用變量存儲(chǔ)上一次鼠標(biāo)的位置,當(dāng)拖動(dòng)鼠標(biāo)時(shí),在上一次位置和鼠標(biāo)當(dāng)前位置之間畫線。運(yùn)行這個(gè)程序,然后將draw()方法中給lastX和lastY賦值的兩條語句注釋掉,再運(yùn)行,看看有什么變化。
即便不要那兩條賦值語句,也有別的簡單辦法來實(shí)現(xiàn)自由畫線,那就是使用變量pmouseX和pmouseY。它們是程序前一幀的鼠標(biāo)位置。下面的代碼就使用了這兩個(gè)變量:
延伸一下,你現(xiàn)在可以編寫這樣一個(gè)復(fù)雜一些的程序:當(dāng)用戶在程序窗口中點(diǎn)擊時(shí),以這些點(diǎn)擊的位置為頂點(diǎn)畫出圖形。這個(gè)代碼示例有幾個(gè)代碼段,你需要一個(gè)一個(gè)地閱讀。第一段是定義一個(gè)類。
首先,你要寫出單詞class和類名(如Point),以及一個(gè)左大括號(hào)。左大括號(hào)表示你即將開始定義方法和數(shù)據(jù)。
class Point{
然后,定義兩個(gè)變量來存放點(diǎn)的坐標(biāo)。
下面是該類的構(gòu)造函數(shù)。
Point(float _x, float _y){x = _x;y = _y; }這個(gè)構(gòu)造函數(shù)有兩個(gè)形參_x和_y,它執(zhí)行時(shí)會(huì)把這兩個(gè)傳遞進(jìn)來的參數(shù)值賦給x和y。一個(gè)Point類的具體實(shí)例(對(duì)象)是點(diǎn),可以存放用戶鼠標(biāo)點(diǎn)擊的位置。
既然點(diǎn)類Point已經(jīng)定義好,現(xiàn)在可以創(chuàng)建若干個(gè)點(diǎn)對(duì)象。假設(shè)我們最多允許繪制六邊形,為了存儲(chǔ)6個(gè)點(diǎn),就需要建立一個(gè)點(diǎn)數(shù)組,它的每個(gè)元素都是一個(gè)點(diǎn)的實(shí)例。
還要做的一件事情是編寫mousePressed()方法,以便在鼠標(biāo)按下時(shí),將mouseX和mouseY保存在點(diǎn)數(shù)組中。另外,還要在draw()方法中利用這些點(diǎn)繪制多邊形。示例3-12中,由于程序較為復(fù)雜,故特意將它劃分成多個(gè)步驟。
示例3-12:point.pde
在draw()方法中,用background()方法將背景色設(shè)置為白色,用fill()方法將填充色設(shè)置為黑色,然后用for循環(huán)來繪制那些點(diǎn)構(gòu)成的多邊形:
void draw(){background(255);fill(0);beginShape();for(int i = 0; i<pts.length; i++){一開始的時(shí)候,點(diǎn)數(shù)組pts中的每個(gè)元素都是null。為了避免錯(cuò)誤,對(duì)于每個(gè)元素,都需要確保它是點(diǎn)的實(shí)例才能將它納入到多邊形頂點(diǎn)中:
if(pts[i] != null) {如果它不是null,可以用它來建立一個(gè)頂點(diǎn):
vertex(pts[i].x, pts[i].y);}}結(jié)束繪圖:
endShape(); }當(dāng)用戶按下鼠標(biāo),要將鼠標(biāo)位置存儲(chǔ)到pts數(shù)組中備用。具體怎么做呢?可以建立一個(gè)新的Point對(duì)象,并將當(dāng)前的mouseX和mouseY傳遞給它,并將這個(gè)對(duì)象存儲(chǔ)到pts數(shù)組中第count個(gè)元素那個(gè)位置:
void mousePressed(){if(count > 5){count = 0;}Point newPoint = new Point(mouseX, mouseY);pts[count] = newPoint;count++; }好了。再寫一遍Point類的完整聲明:
class Point{float x;float y;Point(float _x, float _y){x = _x;y = _y;} }那么,當(dāng)你在程序窗口中點(diǎn)擊時(shí)發(fā)生了什么?修改Point類的構(gòu)造函數(shù):
Point(float _x, float _y){println(" x is: "+_x+" and y is "+_y);x = _x;y = _y;}如此一來,每當(dāng)你在程序窗口中點(diǎn)擊時(shí),你將會(huì)看到在控制臺(tái)輸出一行信息(當(dāng)然,具體數(shù)據(jù)跟你點(diǎn)擊的位置有關(guān)):
x is: 262.0 and y is 51.0 x is: 234.0 and y is 193.0 x is: 362.0 and y is 274.0 x is: 125.0 and y is 340.0 x is: 17.0 and y is 155.0那么,這一切是怎么發(fā)生的呢?再看看mousePressed()方法:
void mousePressed(){ ...Point newPoint = new Point(mouseX, mouseY);pts[count] = newPoint; }每當(dāng)用戶按下鼠標(biāo)按鍵時(shí),mousePressed()方法被調(diào)用執(zhí)行。它調(diào)用Point類的構(gòu)造函數(shù),建立了一個(gè)點(diǎn)對(duì)象,并將mouseX和mouseY傳遞給這個(gè)點(diǎn)。然后將這個(gè)點(diǎn)存儲(chǔ)到pts數(shù)組中,以便draw()方法能使用這些點(diǎn)對(duì)象來建立多邊形頂點(diǎn)。
前面的例子用到了for循環(huán)、類、數(shù)組以及vertex()方法。該代碼示例有些難度,需要認(rèn)真思考才能理解。第5章將介紹關(guān)于類的更多內(nèi)容。
3.5.4 變量 keyPressed和key
你或許想知道用戶是否按了鍵盤鍵。你可以判斷用戶是否按鍵,并且可以獲知用戶按下了哪個(gè)鍵。要實(shí)現(xiàn)這個(gè)目的,有兩種方式。第一種是在draw()方法中檢查keyPressed變量:
void draw() {if(keyPressed) {print(" you pressed "+key);} }注意,你可以通過key變量來判斷用戶按下了哪個(gè)鍵。Processing應(yīng)用程序?qū)⒚總€(gè)鍵都存儲(chǔ)在內(nèi)置變量中。此外,Processing還定義了一個(gè)keyPressed()方法,當(dāng)用戶按鍵時(shí),這個(gè)方法會(huì)被調(diào)用。你可以像使用mousePressed()或mouseMoved()方法一樣來使用keyPressed()方法:
void keyPressed(){print(" you're pressing a key \n that key is "+key); }處理按鍵的程序代碼都應(yīng)該放到keyPressed()方法中。例如,游戲中用戶按下方向鍵,或者用戶在一個(gè)文本框中輸入名字后按下了回車鍵。
注意: keyPressed()是一個(gè)方法,而keyPressed是一個(gè)屬性(變量)。它們除了名字相同之外,其他方面有很大區(qū)別。只有當(dāng)用戶按鍵時(shí),keyPressed()方法才會(huì)被調(diào)用執(zhí)行;而如果對(duì)keyPressed變量的檢測(cè)是在draw()循環(huán)中進(jìn)行的,你按鍵的時(shí)間是在兩次draw()執(zhí)行的空檔,那么程序是檢測(cè)不到的。
訪談:Ben Fry
Ben Fry和Casey Reas同為Processing項(xiàng)目的發(fā)起人。Ben Fry在全球很多地方都做過關(guān)于數(shù)據(jù)可視化、媒體藝術(shù)和計(jì)算機(jī)科學(xué)的演講。他還出版了兩本書,一本是《Processing: A Programming Handbook for Visual Designers and Artists》(由他和Casey Reas合著,麻省理工學(xué)院出版社),另一本是《Visualizing Data》(O扲eilly出版社)。另外他還創(chuàng)建了大量的數(shù)據(jù)可視化作品、圖表,并撰寫了不少論文。
是什么令你對(duì)數(shù)據(jù)可視化產(chǎn)生興趣的?是出于審美考慮,還是為了解決數(shù)據(jù)處理的問題,抑或兩者皆有?
Ben: 都有。在年少時(shí)我就對(duì)平面設(shè)計(jì)和計(jì)算機(jī)科學(xué)產(chǎn)生了興趣:我在中學(xué)時(shí)就覺得廣告、標(biāo)志和排印很有趣,而編寫我的第一個(gè)BASIC程序還要更早。讀大學(xué)時(shí),我學(xué)習(xí)平面設(shè)計(jì),尤其喜歡資訊設(shè)計(jì)(和動(dòng)畫以及動(dòng)態(tài)信息顯示)。有很長一段時(shí)間,我以為我會(huì)一直從事UI設(shè)計(jì),事實(shí)上我的實(shí)習(xí)和第一份工作都是這個(gè)方面的。然而事實(shí)并非如此,在麻省理工學(xué)院研究生院,我將設(shè)計(jì)和可視化結(jié)合在一起。實(shí)際上,在學(xué)校里我的學(xué)習(xí)重點(diǎn)主要是平面設(shè)計(jì),以及少量計(jì)算機(jī)科學(xué)(至少本科是這樣)。設(shè)計(jì)是主要科目,因?yàn)槲艺J(rèn)為它會(huì)給我?guī)砀嗟撵`活性以及教我如何去思考。我被領(lǐng)向計(jì)算藝術(shù),由于它融合了這兩個(gè)(當(dāng)時(shí))完全不同的興趣點(diǎn)。沮喪了幾個(gè)月,我意識(shí)到我不再是跨學(xué)科的了,因?yàn)槲业膬蓚€(gè)感興趣學(xué)科融合了。好的一面是,我可以專注于這種直接的融合;而不好的一面是,我不能像年輕時(shí)想的那樣去單獨(dú)對(duì)待這兩個(gè)學(xué)科了。
我覺得你的工作中有一個(gè)中心思想,那就是關(guān)于設(shè)計(jì)師在社會(huì)、科學(xué)、計(jì)算以及其他方面如何定位的問題,在那些方面,視覺設(shè)計(jì)通常被當(dāng)做次要因素。這種評(píng)價(jià)正確嗎?在其他那些低估了視覺設(shè)計(jì)價(jià)值的地方,你認(rèn)為視覺設(shè)計(jì)還是必需的嗎?
Ben: 事實(shí)確實(shí)如此,凡事有兩面。首先,社會(huì)、科學(xué)、計(jì)算這些方面是我最喜歡和好奇的。其次,務(wù)實(shí)地說,對(duì)那些問題感興趣的人越來越少,所以我能為自己開辟出一個(gè)新的方向。
看到你所做的工作,我經(jīng)常會(huì)有“哇哦”這樣的反應(yīng)。起初,視覺的美感和復(fù)雜性確實(shí)震撼了我,接著我才意識(shí)到什么是可視化。這些工作是你有目的地做的,還是你早已聽聞,或本身就很想做的?
Ben: 人們傾向于要么讓事物更美,要么讓它們更有信息含量,很少把它們放在一起考慮。尤其是在處理信息的時(shí)候,這種非此即彼的態(tài)度更是隨處可見。但是除非有東西兼具這兩種特性,否則我不太會(huì)感覺滿意。我希望一個(gè)項(xiàng)目在得到一聲“喔”的驚嘆以后,仍然是有價(jià)值的。但是,那些漂亮的部分其實(shí)很容易做出來。在某種程度上,我僅僅處理那些我想看的東西,我希望它們不僅有視覺刺激,還有思維上的刺激。當(dāng)然,這就進(jìn)入了一個(gè)十分主觀的領(lǐng)域,而且,我也不愿意把我的作品當(dāng)做“美麗的東西”——那種意見很個(gè)人化,受眾有可能同意,也有可能不同意。如果我的工作在人們面前只得到一聲“喔”,隨后什么也沒有,我會(huì)認(rèn)為這是一種失敗。如果一幅圖沒有讓人們好奇到想要深入挖掘,沒有讓人們對(duì)其主題產(chǎn)生好奇,那么我就沒做好我的工作(至少在我看來是這樣)。
一件像“aligning humans and animals”這樣的圖形塊既是一個(gè)很好的例證,也是對(duì)大量信息的合理、科學(xué)、嚴(yán)謹(jǐn)?shù)陌凳尽_@樣一來,它讓我想起了一些當(dāng)代藝術(shù)家(想到卡斯滕·尼古拉)。他們處理復(fù)雜的概念,使它們醒目和易讀。您能否談?wù)劻钅械秸駣^的一些當(dāng)代藝術(shù)家或設(shè)計(jì)師?
Ben: 我從排印、運(yùn)動(dòng)圖形和電影中得到大量靈感。但我難以把它們羅列起來,因?yàn)樗鼈兛偸沁@里和那里的一些小花絮:庫布里克電影藝術(shù),好看的電影資訊圖像,馬修·卡特的印刷字型中的美和結(jié)構(gòu)的平衡。我辦了一個(gè)類似博客(http://benfry.com)的網(wǎng)站,這樣我就可以把這些東西寫下來,并收集在這個(gè)地方。當(dāng)我看到一些東西,比如,科學(xué)家澆注熔融鋁到蟻洞(http://benfry.com/writing/archives/98),以便看見蟻洞結(jié)構(gòu)(待鋁冷卻并除去污垢后),我就可以把這個(gè)事情發(fā)布到博客上。但這是我固執(zhí)的想法——把下面這些東西聯(lián)系起來:把蟻群的有機(jī)形狀與類似的形狀聯(lián)系到一起,如加拿大北部纖細(xì)的湖泊形狀或復(fù)雜的網(wǎng)絡(luò)拓?fù)鋱D。
看你在博客上寫的文章還有你寫的書,你涉及的主題極為廣泛——從排印到棒球選手,再到政府和隱私的插圖——但這些數(shù)據(jù)似乎都一團(tuán)糟。你有沒有方法來尋找主題?
Ben: 這在很大程度上只是出于好奇,但這對(duì)我來說是組織我的思想的方式。我不喜歡讓我的博客、著作等與我的工作直接相關(guān)(它們往往會(huì)混淆我的想法),但我從來都不知道為什么會(huì)這樣。在組織思想時(shí),我很容易理解什么是其中最主要的。在一定程度上,這既能提高寫作能力,也對(duì)健康有益。
至于方法,我努力堅(jiān)持圍繞信息和數(shù)據(jù)的主題,但偏向電影和運(yùn)動(dòng)一些,通常是因?yàn)樗婕袄L圖(與通信有關(guān))或敘述(可視化)。遠(yuǎn)離政治,或者說,遠(yuǎn)離上周的“周六夜現(xiàn)場(chǎng)”中的太空奧運(yùn)會(huì)小品,這對(duì)我是很難的,但我不想掉進(jìn)大眾喜好的圈子,也不希望我的博客是流水賬。
你是否認(rèn)為你的設(shè)計(jì)工作可能讓你遠(yuǎn)離信息可視化并通往更具抽象審美的東西,或者你對(duì)信息類的東西不感興趣?
Ben: 不,我想我反而是太沉迷于信息。它可能帶我遠(yuǎn)離設(shè)計(jì),并進(jìn)入我們?nèi)绾慰创龜?shù)據(jù)的那些方面(例如,沿著博客上一串關(guān)于隱私和安全的博文,弄清楚“我們擁有這些數(shù)據(jù),現(xiàn)在該怎么辦?”)。但我同樣喜歡視覺方面,所以我認(rèn)為我不會(huì)完全放棄它。
開發(fā)Processing,有多少原因是你自己缺乏一個(gè)類似的工具,有多少因素是由于想為他人開發(fā)工具,這兩者你怎么看?
Ben: 嗯,我認(rèn)為,起初這兩個(gè)原因同等重要,但后來更多地是讓Processing成為大家的工具。為陌生人開發(fā)一個(gè)工具所花的時(shí)間比為自己開發(fā)工具要多幾個(gè)數(shù)量級(jí)。就算如此,我們也要把公共的部分做完(即便常常對(duì)我們自己的工作有影響)。
也就是說,它在很大程度上受我自己的工作的驅(qū)動(dòng)——常常是我自己的開發(fā)中用到了一些新東西,然后立即或者很快就去改進(jìn)Processing。說實(shí)話,我們?cè)谟行┑胤?#xff08;如聲音)做得不夠好,因?yàn)镃asey和我在我們自己的工作中都沒有充分利用它們。
我認(rèn)為,Processing更多地是一種“回饋”項(xiàng)目。在我10歲或12歲學(xué)習(xí)編程時(shí),很多人把他們的程序代碼共享給我(無論直接還是間接),我很感激他們。Processing項(xiàng)目也是開放的,有能力的人可以將它往前推進(jìn)。偶爾我看到用Processing開發(fā)出來的作品時(shí),我想過放棄自己開發(fā)項(xiàng)目,而更加努力地開發(fā)Processing。
作為一個(gè)程序員,我真的很喜歡反編譯和程序修正,因?yàn)檫@兩個(gè)不同的過程都圍繞著一件事,那就是代碼的開發(fā)和運(yùn)行。您怎么看?
Ben: 它們都跟人們腦海中的想象有關(guān)……我大致能夠想象出代碼隨時(shí)間變化的樣子,以及正在運(yùn)行的代碼的樣子,但我真的很想看到。我懷疑,得到其他人良好反應(yīng)的圖像未必具有特別的開創(chuàng)性(我們以前看過視覺差異和代碼跟蹤),這有點(diǎn)像看到一個(gè)夢(mèng)想的實(shí)現(xiàn),或閱讀的一篇文章完美地表達(dá)了你的看法,比如對(duì)一個(gè)復(fù)雜的政治局勢(shì)或社會(huì)現(xiàn)象的看法。
關(guān)于Processing的未來,你有一個(gè)清晰的愿景嗎?還是規(guī)模大又活躍的Processing社區(qū)在一定意義上幫助引導(dǎo)該項(xiàng)目?
Ben: 我認(rèn)為社區(qū)已經(jīng)在很多決策上引導(dǎo)我們了。如果你看看我們?cè)陧?xiàng)目剛開始時(shí)的目標(biāo)(在線的Web傳輸,再加上支持象串行I/O這樣的功能、硬件設(shè)備等),再看看項(xiàng)目現(xiàn)在的情況(完整的應(yīng)用程序、圖形加速和許許多多的庫),你會(huì)發(fā)現(xiàn)那只“看不見的手”的確在推動(dòng)。
一些最近的事態(tài)發(fā)展都與在其他語言(JavaScript、Ruby和Python)中使用API有關(guān),起初這并非真的可行,但我真的很興奮。現(xiàn)在社區(qū)真的把它拿過來用了。
是不是有各種各樣的項(xiàng)目,人們并沒有真正用Processing深入處理,而你又希望人們那樣做?
Ben: Casey和我在這個(gè)項(xiàng)目中的個(gè)人目標(biāo)之一是,如果我們讓容易的事情變得更容易,讓困難的事情不那么難,那么項(xiàng)目的總體質(zhì)量水平也許能提高一些,或者換句話說,你可以避免很多由于不專業(yè)而引發(fā)的問題。我認(rèn)為我們還沒有做到我期望的那種成功。
你怎么想到要為非程序員創(chuàng)造一門語言?是Ruby或Python這些“友好”的語言引發(fā)的?還是由你想象中的用戶要做的事情驅(qū)使?或者是發(fā)明教學(xué)語言的想法促成的?
Ben: 這些因素都有,另外還有我們積累的偏好,以及基于過去經(jīng)歷的嚴(yán)苛意見。
但可以肯定的是,我們還沒有創(chuàng)建出一個(gè)最終的語言門類,我們只是試圖將我們知道的集成在一起,并把它朝我們認(rèn)為正確的那個(gè)方向推進(jìn)。如果想要有革命性的改變,我認(rèn)為語法和構(gòu)思模型就得大改。但我們必須衡量實(shí)際(人們接受它離現(xiàn)有語言多遠(yuǎn),以及我們創(chuàng)建的軟件需要運(yùn)行多快)。
除了分析數(shù)據(jù)、理解數(shù)據(jù)的認(rèn)知過程,你也可以讓用戶與它交互工作。你覺得,與數(shù)據(jù)交互的觀念同易讀和廣博地顯示數(shù)據(jù)的觀念是一樣豐富的領(lǐng)域嗎?
Ben: 哦,那絕對(duì)是一個(gè)豐富的領(lǐng)域,因?yàn)樗嗟厣婕拔覀兊母泄俸蜕眢w。有一些事情是要盯著看的,我們抓住并操縱、移動(dòng)它們,看它們做什么(如同看著一個(gè)6個(gè)月大的嬰兒)。 做得越多,我們就能學(xué)得越多。
總結(jié)
以上是生活随笔為你收集整理的《交互式程序设计 第2版》一3.5 捕获简单用户交互行为的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微软雷德蒙德和伦敦地区掀起新一轮裁员 涉
- 下一篇: 边界测试——让BUG现形