成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

為自己做一個簡單記賬簿

數(shù)據(jù)庫
當每個月收到信用卡賬單時,筆者總會又驚又惑。為什么上個月又花了那么多錢?為了有效的管理自己的資金動態(tài),筆者利用SQLite為自己做了一個簡單記賬簿。

每個月收到信用卡賬單時,我總會又驚又惑。上個月怎么又花了那么多錢?看著每一筆出帳流水,猛抓頭皮卻怎么也記不起來這錢是用在了哪兒。痛定思痛,采取行動,我要記賬。作為一個信奉技術能改變世界的IT人,我理所當然的在網(wǎng)上搜索各種電子記賬本。在線的記賬功能不敢用(怕被騷擾),一些單機記賬軟件提供的功能又不是我想要的。

與此同時,最近空下來的時候,我在看SQLite方面的資料。SQLite的簡潔、小巧讓我有些愛不釋手。就此決定給自己做個記賬本,用SQLite作為本地數(shù)據(jù)引擎。

功能概述

我需要的記賬功能比較簡單:

***、記錄每一筆消費,并可以添加需要的標簽。當我查看明細時,能知道自己買了啥。

第二、對我來說,消費只需要分成兩種:‘生活必需消費’和‘享受消費’。每周、每月可以看到這兩種消費所占的比例、金額。

第三、能查看自己近6個月的消費走勢。

根據(jù)這3點需求,我為自己度身定制了這款記賬工具。

圖1是記賬本的啟動框。

程序?qū)右粋€工作線程來檢查記賬程序路徑下是否已存在賬本數(shù)據(jù)庫,若沒有則創(chuàng)建該數(shù)據(jù)庫和所需的表結(jié)構。同時定時器將輪詢檢查結(jié)果。

 (圖1)

圖2是記賬本的主界面。

很多其他記賬軟件把消費分成餐飲,交通,買衣服……或者更細。一筆賬到底歸為哪一類要想個半天,同時出的圖表復雜但又意義不大。

為自己做的賬本只有兩種消費類別,對應兩個大按鈕,點擊即可進入記賬界面。這兩種消費所占的比例和總額是我每月的關注點。

主界面的最下方還有3個按鈕,分別對應‘返回主界面’、‘退出程序’、‘查看報表’。在任何其它界面中,這三個按鈕的圖案、功能都保持一致。

(圖2)

點擊主界面上的綠色或紅色按鈕就會進入到記賬界面。如圖3所示

標題、圖標、主色調(diào)區(qū)分了不同的消費。該界面的設計也是希望最簡化,省去了消費時間選擇框,默認為當前記錄時間。

該界面的一個亮點是‘標簽選擇框’??蛑械臉撕炇莿討B(tài)生成的。系統(tǒng)會取近一個月時間,使用最頻繁的10個標簽來顯示。(代碼分析部分還會展開)

這里記錄的標簽,會出現(xiàn)在后面的明細報表中,這是我用來對賬的。

(圖3)

***來看一下這個小工具能生成的圖表與報表,如圖4所示

該工具能輸出3種報表,分別是消費比例圖,近6月消費走勢圖,消費對賬明細。對于圖表,鼠標至于色塊上方時將顯示消費金額。

這3個報表也本著減少操作,降低復雜度,簡潔好用為宗旨,所以只提供了最必要的功能。

(圖4)

程序結(jié)構

看了工具的界面設計后,讓我們來看一下程序結(jié)構,如圖5所示

(圖5)

整個Solution最主要由3個Project組成。

1. DataAccessLayer.SQLite包裝了對SQLite訪問的方法

2. ForSingle 主程序

3. UserControls 自定義用戶控件

需要說明的是:

這個工具所有界面最下方的3個按鈕保持統(tǒng)一,所以我在UserControls中畫了一個BaseForm(圖中橙色框標出),讓主界面繼承自BaseForm。

其他的每一個界面都做成UserControl,在主程序中控制它們的創(chuàng)建與顯示。如圖中綠色框標出。

SQLite對于本地應用是個不錯的選擇,我使用的是一個包裝成ADO.NET接口的SQLite引擎。以下鏈接供參考:

我使用的類庫:http://sqlite.phxsoftware.com/

SQLite官方網(wǎng)站:http://www.sqlite.org/

#p#

代碼分析

1. 程序啟動

當程序啟動時,需要做一下檢查和初始化工作。我把這些工作都放在啟動框中完成。

Program.cs:

  1. [STAThread]    
  2.  
  3. static void Main()    
  4.  
  5. {    
  6.  
  7.     Application.EnableVisualStyles();    
  8.  
  9.     Application.SetCompatibleTextRenderingDefault(false);    
  10.  
  11.     if (Splash.Instance.ShowDialog() == DialogResult.OK)    
  12.  
  13.      {    
  14.  
  15.          Application.Run(new MainFrame());    
  16.  
  17.      }    
  18.  
  19. }   

以上代碼中的Splash就是啟動對話框。只有當返回DialogResult.OK時,才會啟動主程序。

Splash對話框是一個簡單單例模式的實現(xiàn)。

Splash.cs:

  1. private static Splash _instance;    
  2.  
  3. public static Splash Instance    
  4.  
  5. {    
  6.  
  7.     get   
  8.  
  9.     {    
  10.  
  11.         if (_instance == null)    
  12.  
  13.         {    
  14.  
  15.             _instance = new Splash();    
  16.  
  17.         }    
  18.  
  19.         return _instance;    
  20.  
  21.     }    
  22.  
  23. }   

在Splash的構造過程中,會啟動一個定時器,再會啟動一個工作線程運行初始化程序。

Splash.cs:

  1. private Splash()    
  2.  
  3. {    
  4.  
  5.     InitializeComponent();    
  6.  
  7.     SetDialogInfo();    
  8.  
  9.     Ticker.Start();    
  10.  
  11.     Worker.RunWorkerAsync();    
  12.  
  13. }  

工作線程與定時器之間由標志DBState聯(lián)系起來的,工作線程置標志,定時器輪詢標志。

Splash.cs:

  1. private Timer _ticker;    
  2. public Timer Ticker    
  3. {    
  4.     get   
  5.     {    
  6.         if (_ticker == null)    
  7.         {    
  8.             _ticker = new Timer(this.components);    
  9.             _ticker.Interval = 2000;    
  10.             _ticker.Tick += new System.EventHandler(_ticker_Tick);    
  11.         }    
  12.         return _ticker;    
  13.     }    
  14. }    
  15. private enum DBStateEnum    
  16. {    
  17.     Undefined,    
  18.     Ready,    
  19.     Failed    
  20. }    
  21. private DBStateEnum _dbState = DBStateEnum.Undefined;    
  22. private DBStateEnum DBState    
  23. {    
  24.     get { return _dbState; }    
  25.     set { _dbState = value; }    
  26. }    
  27. private void _ticker_Tick(object sender, System.EventArgs e)    
  28. {    
  29.     if (DBState == DBStateEnum.Ready)    
  30.     {    
  31.         this.DialogResult = DialogResult.OK;    
  32.         this.Close();    
  33.     }    
  34.     else if (DBState == DBStateEnum.Failed)    
  35.     {    
  36.         if (string.IsNullOrEmpty(this.lblMessage.Text))    
  37.         {    
  38.             this.lblMessage.Text = ErrorMessage;    
  39.         }    
  40.         else   
  41.         {    
  42.             this.DialogResult = DialogResult.Cancel;    
  43.             this.Close();    
  44.         }    
  45.     }    
  46. }  

2. 標簽選擇框的繪制

圖3下半部分中有一系列動態(tài)標簽,這些標簽的顯示邏輯為:

從本地SQLite數(shù)據(jù)庫中,查詢出指定消費類別(‘生活必需’或‘奢侈享受’)近一個月中不重復的標簽,按出現(xiàn)頻率倒序排列,并取出前10個

FeeRecorderControl.cs:

  1. private static readonly string getRecentMonthTop10SubCategorySql =    
  2.              @"select    
  3.                SubCategory    
  4.              from    
  5.                AccountRecord    
  6.              where    
  7.                Category = '{0}'    
  8.                and    
  9.                ConsumeDate >= date('now''localtime''-1 month')    
  10.                and    
  11.                ConsumeDate <= datetime('now''localtime')    
  12.                and    
  13.                ifnull(SubCategory, '') <> ''    
  14.              group by    
  15.                SubCategory    
  16.              order by    
  17.                count(*) desc    
  18.              limit 0,10;";   

界面上的繪制標簽區(qū)域其實是一個Panel,每一個標簽是一個Label。

每次添加Label時,需檢查當前將繪制的Label是否會超出Panel的邊界,并相應的進行換行處理或退出循環(huán)。

FeeRecorderControl.cs:

  1. private void InitalizeSubCategoryPanel(string strCategory, Color backColor)    
  2.         {    
  3.             using (SQLiteConnection conn = new SQLiteConnection(SqliteConnString))    
  4.             {    
  5.                 conn.Open();    
  6.                 using (SQLiteCommand cmd = new SQLiteCommand(string.Format(getRecentMonthTop10SubCategorySql, strCategory), conn))    
  7.                 {    
  8.                     using (SQLiteDataReader reader = cmd.ExecuteReader())    
  9.                     {    
  10.                         Point subCategoryLocation = new Point(0, 0);    
  11.                         SubCategoryList.Clear();    
  12.                         plSubCategory.Controls.Clear();    
  13.                         while (reader.Read())    
  14.                         {    
  15.                             string strSubCategory = reader["SubCategory"].ToString();    
  16.                             Label lblSubCategory = new Label();    
  17.                             lblSubCategory.Text = strSubCategory;    
  18.                             lblSubCategory.Font = new Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold,    
  19.                                                            System.Drawing.GraphicsUnit.Point, ((byte) (0)));    
  20.                             lblSubCategory.Width = lblSubCategory.Text.Length*25 + 10;    
  21.                             lblSubCategory.Height = 35;    
  22.                             lblSubCategory.TextAlign = ContentAlignment.MiddleCenter;    
  23.                             lblSubCategory.BackColor = backColor;    
  24.                             lblSubCategory.Click += new EventHandler(lblSubCategory_Click);    
  25.                             if (subCategoryLocation.X + lblSubCategory.Width <= plSubCategory.Width    
  26.                                 && subCategoryLocation.Y + lblSubCategory.Height <= plSubCategory.Height)    
  27.                             {    
  28.                                 lblSubCategory.Location = subCategoryLocation;    
  29.                             }    
  30.                             else if (subCategoryLocation.X + lblSubCategory.Width > plSubCategory.Width     
  31.                                 && subCategoryLocation.Y + lblSubCategory.Height + 5 + lblSubCategory.Height <= plSubCategory.Height)    
  32.                             {    
  33.                                 subCategoryLocation.X = 0;    
  34.                                 subCategoryLocation.Y = subCategoryLocation.Y + lblSubCategory.Height + 5;    
  35.                                 lblSubCategory.Location = subCategoryLocation;    
  36.                             }    
  37.                             else   
  38.                             {    
  39.                                 break;    
  40.                             }    
  41.                             subCategoryLocation.X = subCategoryLocation.X + lblSubCategory.Width + 5;    
  42.                             SubCategoryList.Add(lblSubCategory);    
  43.                         }    
  44.                         plSubCategory.Controls.AddRange(SubCategoryList.ToArray());    
  45.                     }    
  46.                 }    
  47.                 conn.Close();    
  48.             }    
  49.         }  

總結(jié)與思考

1. 我對WinForm的開發(fā)遠沒有對數(shù)據(jù)庫開發(fā)熟悉,大家若發(fā)現(xiàn)紕漏之處,請溫柔指出。

2. 最近用戶體驗是一個熱門詞匯,做軟件除了考慮技術問題之外,更要站在用戶的角度去考慮他們的使用習慣。

3. 我自己非常想把這個記賬工具做成手機版的,但對于移動開發(fā)知之甚少,大家可以進行嘗試與討論,歡迎和我郵件交流。

原文鏈接:http://www.cnblogs.com/DBFocus/archive/2011/02/27/1966203.html

【編輯推薦】

  1. SQLite做為本地緩存應注意的幾大方面
  2. C#中數(shù)據(jù)本地存儲方案之SQLite
  3. 淺析SQLite數(shù)據(jù)庫開發(fā)常用管理工具
  4. Widget開發(fā)心得 解決跳轉(zhuǎn)頁面和SQLite類問題

 

責任編輯:艾婧 來源: 博客園
相關推薦

2015-07-03 11:27:30

程序員自己神器

2020-07-20 10:00:52

Python翻譯工具命令行

2021-12-30 06:59:27

視頻通話網(wǎng)頁

2013-04-18 09:33:57

Windows PhoWindows Pho

2022-12-22 19:22:55

應用開發(fā)鴻蒙

2017-06-30 15:18:24

對賬系統(tǒng)互聯(lián)網(wǎng)

2012-12-17 12:58:18

WebjQuery重構

2023-05-27 21:13:34

FlaskURL裝飾器

2021-11-26 08:33:51

React組件前端

2010-08-11 13:39:16

Flex3.0Flv播放器

2018-01-04 16:04:35

圓環(huán)放大動畫

2021-12-17 10:06:42

鴻蒙HarmonyOS應用

2016-11-23 18:13:44

javascriptrxjsreactivex

2014-04-29 10:50:16

池建強

2019-04-22 10:25:52

程序員技術職場

2021-12-01 07:02:55

Python 記錄器按鍵

2023-12-16 13:21:00

Python元類ORM

2021-05-26 07:53:58

Linux運維Linux系統(tǒng)

2018-09-17 15:12:25

人工智能神經(jīng)網(wǎng)絡編程語言

2022-10-14 17:48:55

D2C代碼vue
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲欧美在线观看 | 久久精品在线 | 国产精品特级毛片一区二区三区 | 欧美一区二区三区日韩 | 黄色大片视频 | 天天干天天干 | 亚洲精品乱码久久久久久蜜桃91 | 婷婷五月色综合 | 麻豆91精品91久久久 | 国产精品久久国产精品99 gif | 天天天天操 | 亚洲精品99999 | 欧美中文在线 | www.国产 | 91视频网 | 日韩在线观看视频一区 | 国产精品成人一区 | 免费一区二区 | 亚洲精品一区久久久久久 | 欧美精品一区二区三 | 日本精品久久 | 亚洲男人的天堂网站 | 香蕉视频一区二区 | 久久精品日产第一区二区三区 | 亚洲国产中文在线 | 一二三区视频 | 欧美成年人视频在线观看 | 国产欧美精品一区 | 精品免费国产视频 | 精品亚洲一区二区三区 | 国产一区亚洲二区三区 | 久久精品一区 | 国产1区2区3区 | 精品久久久久久久 | 一区二区三区在线电影 | 国产日韩欧美一区二区 | 免费观看的黄色网址 | 精品欧美一区二区久久久伦 | 成人三级av| 四虎最新| 精品成人av |