画图板程序
?
最近做一些圖像處理相關的東西 還是有那么一點點心得分享下
第一部分:
做一個畫圖板程序類windows里的mspaint
首先是想到怎么把基本功能實現(xiàn) 鉛筆阿 畫線阿 畫圓 畫框阿 啥的,為了突出咱的不同 咱做一個對圖形進行拖動 調(diào)整大小的功能 。
要對圖形重定義 那么要對圖像保存元數(shù)據(jù)以便以后調(diào)整 說得忽悠點就是序列化啥的 磚家們經(jīng)常這樣講
畫線 鉛筆 畫圓 畫框 這些在.net的graphic里調(diào)用都一句話的事 然后在onpaint里進行重繪就可以了。
明白原理自己去實現(xiàn)也不是不可以 以前我寫過一篇在winfrom里畫直線的文章 只是我們沒有必要再去造輪子。
我們先弄一個工具欄 整個工具切換效果 先拖個menustrip控件 然后加5個菜單項:
寫menustrip的itemclicked事件的代碼, 注意不是菜單項的click事件:
?然后再聲明一個枚舉類型 枚舉5種工具,單擊菜單項的時候進行切換:
private void 畫線ToolStripMenuItem_Click(object sender, EventArgs e) {type = toolType.line; }private void 鉛筆ToolStripMenuItem_Click(object sender, EventArgs e) {type = toolType.pencil; } toolType type; enum toolType {line, pencil,rec }?然后是畫的過程,咱不能直接在窗體上畫 咱得保存元數(shù)據(jù)阿,線段嗎暫時用 Ilist<Point> 就可以 鉛筆用graphicPath 矩形就用 Ilist<Rectangle>
畫的時候根據(jù)鼠標 按下->拖動->釋放 把圖形添加到后臺。onpaint事件的時候把圖形重現(xiàn)。
下面是一些代碼 我說過畫線畫框那些在.net里都是一句話調(diào)用的事,鉛筆工具稍微復雜點 在最后面有說明:
?并且矩形這里也只對從左上起點到右下結(jié)束的這種情況作了處理 其他的情況沒考慮,在完整代碼里功能是實現(xiàn)了的。
還有就是怎么沒有“即時效果” 就是畫線斷跟畫框的拖拽效果,在onpaint最后加上這兩句就可以了:
?當然得加一個mouseDown的bool變量 讓他在鼠標按下時為true 彈起時為false,再加一個tmpMouse的 Point變量? 在鼠標移動時給他賦值。
以上所有源碼下載 猛擊此處
當當當當 現(xiàn)在一個畫圖板出來了吧基本上可以用了吧 挖哈哈 (ˉ▽ˉ;)
對了拖動功能呢?這個嘛其實很簡單, 如果當前是對象選擇工具(最后一個按鈕) 在鼠標按下時把那個坐標拿到所有對象里去檢測 如果有符合的 選定那個圖形。
檢測的方式嘛 自己去搞咯, 看某個點是否在一條線斷上我那個 畫直線 的文章里有 第二部分的源碼里也有。檢測矩形就更簡單啦
鼠標移動的時候看當前是否檢測并選擇了對象 如果有 拖動就是啦,拖動的過程 這還不簡單 更改當前對象的坐標就是啦 point.offset 根據(jù)當前鼠標位置改 不要告訴我你不會哈。
這些所有的在第二部分的源碼里都有。
第二部分:
程序不是完了嗎,為什么還要有第二部分,看完就知道了 并且后面的更精彩 嘿嘿,并且第二部分所有代碼都是重新寫的。
上面那樣依然不是好的結(jié)構(gòu) 為了更系統(tǒng)些包括以后功能的擴展 程序結(jié)構(gòu)的清晰 ,我們得用面向?qū)ο蟮姆绞饺ピO計它 把 數(shù)據(jù)模型 代碼邏輯分離, 功能的分類 定義好
想象一下上中學幾何課的時候在黑板上畫圖,比如這是一個系統(tǒng)。它有黑板(Board類)這個對象對不 它是所有圖形的承載體 包括背景色 粉筆 當前正在畫的圖形 等,
圖形是預定好的 有三角形 矩形 各種圖形(Circle line pencil square)
但是他們都有相同的特性比如在黑板上的位置 線條的顏色 填充顏色 他們有共同的基類(Shape) 這點我們可以通過繼承來實現(xiàn):
來復習下最基本的繼承以及virtual方法實現(xiàn):
class Program {static void Main(string[] args){IList<father> fathers = new List< father>();fathers.Add(new son());fathers.Add(new son());fathers[0].method();fathers[0].method2();} }class father {public virtual void method(){Console.WriteLine("father's method");}public virtual void method2(){Console.WriteLine("father's method2");} } class son : father {public override void method(){Console.WriteLine("son's method");//base.method();} }輸出:
son's method
father's method2
說到底virtual跟override就是面向?qū)ο蟮木A所在, 子類實現(xiàn)了調(diào)用子類的 子類未實現(xiàn)調(diào)用父類的。 包括VC++的MFC到處都用到了這種模式。
原來從C轉(zhuǎn)到C++的也根本沒得這么多亂七八糟的面向?qū)ο笤O計的理論,只是有這么一個概念而已。
這是表現(xiàn)圖形及方法實現(xiàn)部分代碼,這么做的目的就是為了對數(shù)據(jù)模型進行定義 便于擴展,比如我以后沒有畫矩形的需求了 可以把矩形那個類刪掉
以后想畫五角星了 可以增加一個五角星的類 繼承Shape。比如每種圖形都有相同的背景色。可以在Shape 定義showBackground()供每個繼承的對象調(diào)用。
而不用每個都重新實現(xiàn)這個方法。
?
跟計算機相關的東西 特別是程序開發(fā),有些東西是要搞清楚原理的 原理弄懂了 什么都好辦 ,不要只浮于表面的一些啥工具啊技術的 發(fā)現(xiàn)培訓機構(gòu)出來的都有點這種。
最菜的時候弄鉛筆工具 我想用鼠標跟隨的方式不斷drawRectangle 這樣就可以把鼠標筆跡畫出來了,最后發(fā)現(xiàn)鼠標是跟不上的 畫出來斷斷續(xù)續(xù)的,
我弄這個之前也沒有看過其他人的代碼,想想也確實應該這樣實現(xiàn)啊。
原來的鉛筆工具代碼。。。
?
這個看上去有點像橡皮擦哈
百度上搜的東西都是廢的。始終找不到原因 到底是鼠標沒有捕捉到那個點么,事實上鼠標的每一個移動的坐標系統(tǒng)底層都是會捕捉到的 只是畫的速度跟不上,
鼠標移動慢點還好 你說移動快了刷刷的 不斷的drawRectangle多費系統(tǒng)資源啊 怎么可能跟得上 可能它也是根據(jù)CPU時間片來的唄 所以有些就漏掉了唄。
可能有些原理性的東西想想大概也就明白了? 但是你得去琢磨啊 否則做什么程序開發(fā),現(xiàn)在做程序設計的早沒有以前C語言時候那些人的認真跟謹慎了
一天費勁心思去研究那些數(shù)學算法 譚大師的《C程序設計》是本好書 有難度但是不是太難 只要認真看都還是看得懂的。
后來知道了有graphicsPath這個東西做什么用的聽名字就知道啊 然后在鼠標移動的時候不斷的graphicsPath.addLine 把鼠標移動的路徑用graphicsPath連起來
果然一試就成功 就跟Windows里的畫圖板一模一樣 我想他那里面也是采用這種方式吧。現(xiàn)在鉛筆工具代碼 注意沒有用到graphicpath
?
如果循環(huán)里換成 i+=2 則變成虛線,并且值越大虛得越兇 有意思吧 (ˉ▽ˉ;)? 。實際上多邊形也可以用這種方式來做 數(shù)組里兩個一組兩個一組的point值 明白賽。
別忘了加上雙緩沖代碼
this.SetStyle(ControlStyles.UserPaint, true); this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景. this.SetStyle(ControlStyles.DoubleBuffer, true);對圖像指定部分進行清除 達到橡皮擦的效果想起來好像很復雜 其實你反過來想不就得了吧,橡皮擦是一種畫筆 一種特殊的畫筆 背景色的畫筆。
還后onPaint的概念自MFC里就有的并不是winfrom里才有 這是Windows窗體的一個重要概念 必須弄明白。
本來參數(shù)e里就有e.graphics? 以前看到網(wǎng)上在鼠標移動時graphics g=graphics.fromhandle(this.handle)? 就一直這樣用 結(jié)果就是老是一閃一閃的,
這次在onpaint直接用e.graphics就不閃了。可見onpaint函數(shù)是直接接管底層的windwos重繪消息 有特別作用的 是不一樣的。有.net了 有winform了 方便了
所有的都是基于托管平臺編程了 我們不用去處理底層windows消息了 于是我們不明白原理了。
還有就是做這種繪圖或者即時性效果的代碼里邊 效率很重要,因為要不斷的重繪不斷的重繪可能每秒鐘那段代碼都被運行無數(shù)次了。
代碼需要優(yōu)化 包括各種條件判斷 這樣可以提高效率 一條 確保在真正需要的時候代碼才會被執(zhí)行 學校里那些爛代碼就不要整到里面了 都是從爛代碼過來的唄。
程序的設計也是很重要的 本人從不在winform里整些亂七八糟的代碼 winfrom里只負責調(diào)用? 哪個類繼承哪個類? 程序結(jié)構(gòu)整整潔潔的 多好。
又講了這么多沒用的
最后是畫圖板最終程序源碼 猛擊此處 怕有的朋友運行不起是在.net2.0模式下編譯的,這里就是個學習的地方 別藏著掖著 整個東西出來還不給源碼給別人研究 多煩啊
如果有用了咱的代碼的請留個名兒哈。
程序還有諸多未完善的地方比如橢圓區(qū)域的判定 變形 等 望改進。橢圓的拖動功能暫未實現(xiàn) 其他的都OK。
還有拖動時圖形抓取的容差是5個像素 針對線段? 抓取拖動的過程沒有任何顏色跟光標的變化 。同鞋們注意咯 免得說俺功能沒實現(xiàn)哈。
其實畫圖板不難 真諦不難 就算你要做成矢量的 可進行后處理的 可拖動的 變形的 多圖層的 就算做到photoshop那樣 也不是什么很困難的事 大家可以看到在《圖片裁剪效果》的文章里alpha透明效果圓角矩形等等我都已經(jīng)實現(xiàn)了。這個實際上不算圖像處理哈 ,要做專門的圖象處理需要有專門的理論 算法? 高數(shù) 平面幾何等等 本人承認在這方面還欠缺 還需努力學習 加油。
又是熬夜寫這個鬼東東 靠 五點多了。
轉(zhuǎn)載于:https://www.cnblogs.com/assassinx/archive/2011/11/02/2179348.html
總結(jié)
- 上一篇: 绘画上色教程(手绘板绘画时如何涂色)
- 下一篇: TP-Link TL-WDR8620 V