首先我註明以下的源碼百分之一百原著,如果想轉載,請列明出處。敬請尊重知識產權,多謝。
由於我購買了的 LCD 是用 I2C方式連接的,所以以下我假設大家的 LCD 也是用 I2C,大小為:4行 x 20字。整個 MENU Library是由四個 class 組成:LCD_MENU、MENU_ITEM、CONTENT 和 LINETEXT。我的簡單構想是每個 LCD_MENU功能表類都有一串 linked list的MENU_ITEM選項類物件,並且給 LCD_MENU的Items指著。而每個 MENU_ITEM物件的Main_Menu指著其所屬的功能表物件;Sub_Menu 指著其子功能表物件;Prev_Menu則指著上一層功能表物件(用以返回上一層功能表單);MENU_ITEM物件中的Selected就是使用者指著目前所選的項目;而MENU_ITEM物件中的Content_Page,就是指著該選項被 Enter 選取後,所顯示的內容物件( CONTENT )。內容物件裡有一串 linked list的LINETEXT字行類物件,並給CONTENT 物件中的p_Head指著開始位置。
//------------------------------------------------------------------------------
//檔案: LCD_MENU.h
//
//作者:Anthony Lee (Dephi.Ktop: skcc)
//
//日期:二零一四年二月一日
//
//功能:完整功能表(菜單)類封裝,提供卷頁瀏覽功能表。
//------------------------------------------------------------------------------
#ifndef LCD_MENU_h
#define LCD_MENU_h
#include "LiquidCrystal_I2C.h"
//如果你的LCD 是20字,請將 MAX_SCREEN_CHAR 設成 19 及 MAX_CHAR_BUFFER 設成 20
#define MAX_SCREEN_CHAR 19
#define MAX_CHAR_BUFFER 20
//如果你的LCD 是 4行,請將 MAX_ROW 設成 4
#define MAX_ROW 4
class LINETEXT
{
public:
int Line_Num;
char Line_Text[ MAX_CHAR_BUFFER ];
LINETEXT *p_Previous;
LINETEXT *p_Next;
public:
LINETEXT();
};
class CONTENT
{
public:
LINETEXT *p_Head;
int LineCount;
int n_select;
LINETEXT *Selected;
public:
CONTENT();
void Add_Line( char *str_text );
int Update_Line( int line_num, char * str_text );
int Delete_Line( int line_num );
void Clear_All();
void init();
};
class MENU_ITEM
{
public:
int Item_ID;
char Item_Name[ MAX_CHAR_BUFFER ];
void *Main_Menu;
void *Prev_Menu;
void *Sub_Menu;
MENU_ITEM *Prev_Item;
MENU_ITEM *Next_Item;
CONTENT *Content_Page;
public:
MENU_ITEM( int a_item_id, char *a_item_name, void* a_main_menu, void* a_prev_menu, void* a_sub_menu, CONTENT* a_contentpage );
}; //End of class MENU_ITEM
class LCD_MENU
{
public:
char MenuTitle[ MAX_CHAR_BUFFER ];
int ItemCount;
MENU_ITEM *Items;
MENU_ITEM *Selected;
int n_select;
CONTENT *Content_Page;
public:
LCD_MENU( char *a_title );
void Add_Item( MENU_ITEM *a_item );
void init();
//----------- User reactions -------
void Action_Up();
void Action_Down();
void *Action_Enter();
void *Action_Back();
}; //End of class LCD_MENU
void CopyString(char *dest, char *src, int buffersize );
void LCD_Show( LiquidCrystal_I2C *screen, LCD_MENU *p_menu );
void Display_Menu( LiquidCrystal_I2C *screen, LCD_MENU *p_menu );
void Display_Content( LiquidCrystal_I2C *screen, CONTENT *p_content );
#endif
//------------------------------------------------------------------------------
//檔案: LCD_MENU.cpp
//
//作者:Anthony Lee (Dephi.Ktop: skcc)
//
//日期:二零一四年二月一日
//
//
// 如需轉載請列明出處,請尊重知識產權。
//
//------------------------------------------------------------------------------
#include "LCD_MENU.h"
//------------------------------------------------------------------------------
//------- String Tools -------
void CopyString(char *dest, char *src, int buffersize )
{
memset( dest, 0, buffersize);
int str_l = strlen( src );
if( str_l > buffersize )
memcpy( dest, src, buffersize-1 );
else
memcpy( dest, src, str_l );
}
//------------------------------------------------------------------------------
//------- Display Entry Function --------
void LCD_Show( LiquidCrystal_I2C *screen, LCD_MENU *p_menu )
{
screen->clear();
if( p_menu->Content_Page != NULL )
{
if( p_menu->Content_Page->LineCount > 0 )
{
Display_Content( screen, p_menu->Content_Page );
}
else
Display_Menu( screen, p_menu );
}
else
Display_Menu( screen, p_menu );
}
//------------------------------------------------------------------------------
//------- Display Menu Items --------
void Display_Menu( LiquidCrystal_I2C *screen, LCD_MENU *p_menu )
{
char buffer[ MAX_CHAR_BUFFER ];
screen->setCursor(0,0);
memset( buffer, 0, MAX_CHAR_BUFFER);
sprintf( buffer,"[ %s ]", p_menu->MenuTitle );
screen->print( buffer );
int n_end;
int n_start;
int n_page;
int row = 0;
//Found the start item ans end item...
MENU_ITEM *p_start_item;
MENU_ITEM *p_end_item;
p_start_item = p_menu->Items;
p_end_item = p_menu->Items;
if( p_menu->n_select < (MAX_ROW - 1) )
{
n_start = 0;
}
else
{
n_page = p_menu->n_select / (MAX_ROW - 1);
n_start = n_page * (MAX_ROW - 1);
}
if( (n_start + MAX_ROW - 1) > p_menu->ItemCount )
n_end = p_menu->ItemCount;
else
n_end = n_start + MAX_ROW - 1;
for( int i=0; i
for( int i=0; i
MENU_ITEM *p_item = p_start_item;
while( p_item != p_end_item )
{
row = row + 1;
if( p_menu->Selected == p_item )
{
screen->setCursor( 0, row );
screen->print( ">" );
}
screen->setCursor( 1, row );
screen->print( p_item->Item_Name );
p_item = p_item->Next_Item;
}
}
//------------------------------------------------------------------------------
//------- Display Conent --------
void Display_Content( LiquidCrystal_I2C *screen, CONTENT *p_content )
{
char buffer[ MAX_CHAR_BUFFER ];
int n_end;
int n_start;
int n_page;
int row = -1;
if( p_content->n_select < (MAX_ROW) )
{
n_start = 0;
}
else
{
n_page = p_content->n_select / (MAX_ROW);
n_start = n_page * (MAX_ROW);
}
if( (n_start + MAX_ROW) > p_content->LineCount )
n_end = p_content->LineCount;
else
n_end = n_start + MAX_ROW;
LINETEXT *p_start_line;
LINETEXT *p_end_line;
p_start_line = p_content->p_Head;
p_end_line = p_content->p_Head;
for( int i=0; i
for( int i=0; i
LINETEXT *p_line = p_start_line;
while( p_line != p_end_line )
{
row = row + 1;
if( p_content->Selected == p_line )
{
screen->setCursor( 0, row );
screen->print( ">" );
}
screen->setCursor( 1, row );
screen->print( p_line->Line_Text );
p_line = p_line->p_Next;
}
}
//------------------------------------------------------------------------------
LINETEXT::LINETEXT()
{
memset( Line_Text, 0, MAX_CHAR_BUFFER);
Line_Num = 0;
p_Previous = NULL;
p_Next = NULL;
}
//------------------------------------------------------------------------------
CONTENT::CONTENT()
{
LineCount = 0;
p_Head = NULL;
}
//------------------------------------------------------------------------------
void CONTENT::init()
{
n_select = 0;
Selected = p_Head;
}
//------------------------------------------------------------------------------
void CONTENT::Add_Line( char *str_text )
{
//Prepare the LINETEXT...
LINETEXT *a_line = new LINETEXT();
CopyString( a_line->Line_Text, str_text, MAX_CHAR_BUFFER - 1 );
LINETEXT *p_Line = p_Head;
if( p_Line != NULL )
{
while( p_Line->p_Next != NULL )
{
p_Line = p_Line->p_Next;
}
p_Line->p_Next = a_line;
a_line->p_Previous = p_Line;
a_line->p_Next = NULL;
}
else
{
p_Head = a_line;
p_Head->p_Previous = NULL;
p_Head->p_Next = NULL;
}
a_line->Line_Num = LineCount;
LineCount++;
}
//------------------------------------------------------------------------------
int CONTENT::Update_Line( int line_num, char * a_text )
{
//Locate the line....
LINETEXT *p_Line = p_Head;
while( p_Line != NULL )
{
if( p_Line->Line_Num == line_num )
{
CopyString( p_Line->Line_Text, a_text, MAX_CHAR_BUFFER );
return( 1 );
}
p_Line = p_Line->p_Next;
}
return( -1 );
}
//------------------------------------------------------------------------------
int CONTENT::Delete_Line( int line_num )
{
//Locate the line....
LINETEXT *p_Line = p_Head;
LINETEXT *p_PrevNode, *p_NextNode;
int ln = 0;
if( p_Line == NULL )
{
LineCount = 0;
p_Head = NULL;
init();
return(-1);
}
while( p_Line != NULL )
{
if( p_Line->Line_Num == line_num )
{
p_PrevNode = p_Line->p_Previous;
p_NextNode = p_Line->p_Next;
delete p_Line;
p_PrevNode->p_Next = p_NextNode;
p_NextNode->p_Previous = p_PrevNode;
//Re-arrange the line num...
p_Line = p_Head;
while( p_Line != NULL )
{
p_Line->Line_Num = ln;
ln++;
p_Line = p_Line->p_Next;
}
LineCount = ln;
init();
return( 1 );
}
p_Line = p_Line->p_Next;
}
return( -1 );
}
//------------------------------------------------------------------------------
void CONTENT::Clear_All()
{
LINETEXT *p_PrevNode;
//Get the rear line node...
LINETEXT *p_RearLine = p_Head;
if( p_RearLine == NULL )
{
LineCount = 0;
p_Head = NULL;
init();
return;
}
while( p_RearLine->p_Next != NULL )
{
p_RearLine = p_RearLine->p_Next;
}
while( p_RearLine->p_Previous != NULL )
{
p_PrevNode = p_RearLine->p_Previous;
delete p_RearLine;
p_PrevNode->p_Next = NULL;
p_RearLine = p_PrevNode;
}
LineCount = 0;
p_Head = NULL;
init();
}
//------------------------------------------------------------------------------
MENU_ITEM::MENU_ITEM( int a_item_id, char *a_item_name, void* a_main_menu, void* a_prev_menu, void* a_sub_menu, CONTENT* a_contentpage )
{
Item_ID = a_item_id;
CopyString( Item_Name, a_item_name, MAX_CHAR_BUFFER );
Main_Menu = a_main_menu;
Prev_Menu = a_prev_menu;
Sub_Menu = a_sub_menu;
Content_Page = a_contentpage;
Prev_Item = NULL;
Next_Item = NULL;
}
//------------------------------------------------------------------------------
LCD_MENU::LCD_MENU( char *a_title )
{
CopyString( MenuTitle, a_title, MAX_CHAR_BUFFER );
Items = NULL;
ItemCount = 0;
}
//------------------------------------------------------------------------------
void LCD_MENU::Add_Item( MENU_ITEM *a_item )
{
MENU_ITEM *p_Item = Items;
if( p_Item != NULL )
{
while( p_Item->Next_Item != NULL )
{
p_Item = p_Item->Next_Item;
}
p_Item->Next_Item = a_item;
a_item->Prev_Item = p_Item;
}
else
{
Items = a_item;
Items->Prev_Item = NULL;
}
a_item->Next_Item = NULL;
ItemCount++;
}
//------------------------------------------------------------------------------
void LCD_MENU::init()
{
n_select = 0;
Selected = Items;
Content_Page = NULL;
}
//------------------------------------------------------------------------------
void LCD_MENU::Action_Up()
{
MENU_ITEM *p_item = Items;
if( Content_Page == NULL )
{
if( n_select > 0 )
{
n_select = n_select - 1;
Selected = Selected->Prev_Item;
}
}
else
{
if( Content_Page->n_select > 0 )
{
Content_Page->n_select = Content_Page->n_select - 1;
Content_Page->Selected = Content_Page->Selected->p_Previous;
}
}
}
//------------------------------------------------------------------------------
void LCD_MENU::Action_Down()
{
MENU_ITEM *p_item = Items;
if( Content_Page == NULL )
{
if( n_select < (ItemCount - 1) )
{
n_select = n_select + 1;
Selected = Selected->Next_Item;
}
}
else
{
if( Content_Page->n_select < (Content_Page->LineCount - 1))
{
Content_Page->n_select = Content_Page->n_select + 1;
Content_Page->Selected = Content_Page->Selected->p_Next;
}
}
}
//------------------------------------------------------------------------------
void *LCD_MENU::Action_Enter()
{
if( Selected->Content_Page != NULL )
{
Content_Page = Selected->Content_Page;
return( this );
}
return( Selected->Sub_Menu );
}
//------------------------------------------------------------------------------
void *LCD_MENU::Action_Back()
{
void* ret_menu;
if( Content_Page != NULL )
{
Content_Page->n_select = 0;
Content_Page->Selected = Content_Page->p_Head;
Content_Page = NULL;
return( this );
}
else
{
ret_menu = Selected->Prev_Menu;
if( ret_menu == NULL )
return( this );
else
{
Selected = Items; //Reset the pointer at the first item;
n_select = 0;
return( ret_menu);
}
}
}
//------------------------------------------------------------------------------
以上就是我的這個 LCD_MENU 物件的源始碼…下回將講述如何使用…密切留意。
沒有留言:
張貼留言