自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

為自己做一個(gè)簡(jiǎn)單記賬簿

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

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

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

功能概述

我需要的記賬功能比較簡(jiǎn)單:

***、記錄每一筆消費(fèi),并可以添加需要的標(biāo)簽。當(dāng)我查看明細(xì)時(shí),能知道自己買(mǎi)了啥。

第二、對(duì)我來(lái)說(shuō),消費(fèi)只需要分成兩種:‘生活必需消費(fèi)’和‘享受消費(fèi)’。每周、每月可以看到這兩種消費(fèi)所占的比例、金額。

第三、能查看自己近6個(gè)月的消費(fèi)走勢(shì)。

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

圖1是記賬本的啟動(dòng)框。

程序?qū)?dòng)一個(gè)工作線程來(lái)檢查記賬程序路徑下是否已存在賬本數(shù)據(jù)庫(kù),若沒(méi)有則創(chuàng)建該數(shù)據(jù)庫(kù)和所需的表結(jié)構(gòu)。同時(shí)定時(shí)器將輪詢檢查結(jié)果。

 (圖1)

圖2是記賬本的主界面。

很多其他記賬軟件把消費(fèi)分成餐飲,交通,買(mǎi)衣服……或者更細(xì)。一筆賬到底歸為哪一類(lèi)要想個(gè)半天,同時(shí)出的圖表復(fù)雜但又意義不大。

為自己做的賬本只有兩種消費(fèi)類(lèi)別,對(duì)應(yīng)兩個(gè)大按鈕,點(diǎn)擊即可進(jìn)入記賬界面。這兩種消費(fèi)所占的比例和總額是我每月的關(guān)注點(diǎn)。

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

(圖2)

點(diǎn)擊主界面上的綠色或紅色按鈕就會(huì)進(jìn)入到記賬界面。如圖3所示

標(biāo)題、圖標(biāo)、主色調(diào)區(qū)分了不同的消費(fèi)。該界面的設(shè)計(jì)也是希望最簡(jiǎn)化,省去了消費(fèi)時(shí)間選擇框,默認(rèn)為當(dāng)前記錄時(shí)間。

該界面的一個(gè)亮點(diǎn)是‘標(biāo)簽選擇框’??蛑械臉?biāo)簽是動(dòng)態(tài)生成的。系統(tǒng)會(huì)取近一個(gè)月時(shí)間,使用最頻繁的10個(gè)標(biāo)簽來(lái)顯示。(代碼分析部分還會(huì)展開(kāi))

這里記錄的標(biāo)簽,會(huì)出現(xiàn)在后面的明細(xì)報(bào)表中,這是我用來(lái)對(duì)賬的。

(圖3)

***來(lái)看一下這個(gè)小工具能生成的圖表與報(bào)表,如圖4所示

該工具能輸出3種報(bào)表,分別是消費(fèi)比例圖,近6月消費(fèi)走勢(shì)圖,消費(fèi)對(duì)賬明細(xì)。對(duì)于圖表,鼠標(biāo)至于色塊上方時(shí)將顯示消費(fèi)金額。

這3個(gè)報(bào)表也本著減少操作,降低復(fù)雜度,簡(jiǎn)潔好用為宗旨,所以只提供了最必要的功能。

(圖4)

程序結(jié)構(gòu)

看了工具的界面設(shè)計(jì)后,讓我們來(lái)看一下程序結(jié)構(gòu),如圖5所示

(圖5)

整個(gè)Solution最主要由3個(gè)Project組成。

1. DataAccessLayer.SQLite包裝了對(duì)SQLite訪問(wèn)的方法

2. ForSingle 主程序

3. UserControls 自定義用戶控件

需要說(shuō)明的是:

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

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

SQLite對(duì)于本地應(yīng)用是個(gè)不錯(cuò)的選擇,我使用的是一個(gè)包裝成ADO.NET接口的SQLite引擎。以下鏈接供參考:

我使用的類(lèi)庫(kù):http://sqlite.phxsoftware.com/

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

#p#

代碼分析

1. 程序啟動(dòng)

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

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就是啟動(dòng)對(duì)話框。只有當(dāng)返回DialogResult.OK時(shí),才會(huì)啟動(dòng)主程序。

Splash對(duì)話框是一個(gè)簡(jiǎn)單單例模式的實(shí)現(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的構(gòu)造過(guò)程中,會(huì)啟動(dòng)一個(gè)定時(shí)器,再會(huì)啟動(dòng)一個(gè)工作線程運(yùn)行初始化程序。

Splash.cs:

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

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

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. 標(biāo)簽選擇框的繪制

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

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

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;";   

界面上的繪制標(biāo)簽區(qū)域其實(shí)是一個(gè)Panel,每一個(gè)標(biāo)簽是一個(gè)Label。

每次添加Label時(shí),需檢查當(dāng)前將繪制的Label是否會(huì)超出Panel的邊界,并相應(yīng)的進(jìn)行換行處理或退出循環(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. 我對(duì)WinForm的開(kāi)發(fā)遠(yuǎn)沒(méi)有對(duì)數(shù)據(jù)庫(kù)開(kāi)發(fā)熟悉,大家若發(fā)現(xiàn)紕漏之處,請(qǐng)溫柔指出。

2. 最近用戶體驗(yàn)是一個(gè)熱門(mén)詞匯,做軟件除了考慮技術(shù)問(wèn)題之外,更要站在用戶的角度去考慮他們的使用習(xí)慣。

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

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

【編輯推薦】

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

 

責(zé)任編輯:艾婧 來(lái)源: 博客園
相關(guān)推薦

2015-07-03 11:27:30

程序員自己神器

2020-07-20 10:00:52

Python翻譯工具命令行

2021-12-30 06:59:27

視頻通話網(wǎng)頁(yè)

2013-04-18 09:33:57

Windows PhoWindows Pho

2022-12-22 19:22:55

應(yīng)用開(kāi)發(fā)鴻蒙

2012-12-17 12:58:18

WebjQuery重構(gòu)

2023-05-27 21:13:34

FlaskURL裝飾器

2017-06-30 15:18:24

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

2021-11-26 08:33:51

React組件前端

2010-08-11 13:39:16

Flex3.0Flv播放器

2016-11-23 18:13:44

javascriptrxjsreactivex

2018-01-04 16:04:35

圓環(huán)放大動(dòng)畫(huà)

2021-12-17 10:06:42

鴻蒙HarmonyOS應(yīng)用

2019-04-22 10:25:52

程序員技術(shù)職場(chǎng)

2021-12-01 07:02:55

Python 記錄器按鍵

2014-04-29 10:50:16

池建強(qiáng)

2023-12-16 13:21:00

Python元類(lèi)ORM

2021-05-26 07:53:58

Linux運(yùn)維Linux系統(tǒng)

2018-09-17 15:12:25

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

2022-10-14 17:48:55

D2C代碼vue
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)