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