星期三, 九月 06, 2006

为OpenFile通用对话框增添预展功能

为OpenFile通用对话框增添预展功能
  用户使用Window应用程序时,经常要打开文件,可有时用户打开文件时却打开了一个不是要求的文件,这显得非常麻烦。因此,许多应用程序便给OpenFile通用对话框增添了预展功能,使得用户在选择文件时,可以先预视其内容。在这里,笔者也向你介绍这种功能的编程方法。  WINDOW的通用对话框OpenFile,在使用,可以安装用户定义的勾子函数。这样,原OpenFile窗口的消息先通过用户的勾子函数过滤。若用户在通用对话框中增加一个Edit控制(此处,以预展文本文件内容为例),处理OpenFile通用对话框中的 CDN_SELCHANGE消息(文件名选择更改消息),即可完成这种功能。  用户定义的勾子函数,WINDOW要求其原形定义如下:  typedef UINT (APIENTRY *LPCCHOOKPROC) (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);  对于OpenFile通用对话框中的一些常见消息,WINDOWS会向用户定义的勾子发送WM_NOTIFY消息,此时,lParam指向一数据结构如下的指针:  typedef struct _OFNOTIFYA
  { NMHDR hdr;
  LPOPENFILENAMEA lpOFN;
  LPSTR pszFile; // May be NULL
  } OFNOTIFYA, FAR *LPOFNOTIFYA;
  而NMHDR在WINDOWS定义如下:  typedef struct tagNMHDR {
  HWND hwndFrom;
  UINT idFrom;
  UINT code;
  } NMHDR;
  其中:hwndFrom 表示发送消息控件的句柄;idFrom表示控件的ID值,而且code表示通告的消息。  在WINDOWS95中通告的消息在commdlg.h中定义如下  #define CDN_SELCHANGE (CDN_FIRST-0x0001) //文件名列表中的文件名更改时发送的消息
  #define CDN_FOLDERCHANGE (CDN_FIRST - 0x0002) //路径更改时发送的消息
  #define CDN_SHAREVIOLATION (CDN_FIRST - 0x0003) //共享按钮改更时发送的消息
  #define CDN_HELP (CDN_FIRST - 0x0004) //HELP按钮按下消息
  #define CDN_FILEOK (CDN_FIRST - 0x0005) //OK按钮按下消息
  因为此处,我们仅处理用户选择的文件名发生更改时,才预展,因此我们定义的勾子函数中,仅处理CDN_SELCHANGE消息。  另外,当什么文件都预展时,用户会发现WINDOWS的速度明显减慢,因此,我决定在OpenFile对话框中增加一个"是否预展"的CheckBox按钮。只有当用户选中了它时才预展。当然,此时,还需要我们自己处理这个CheckBox发送的消息。  以上问题解决后,我们只需要将一个Edit和一个CheckBox增加到一个无窗体的对话框中,并将WINDOWS本身的OpenFile对话框用一个TEXT控件代替,ID值设置为stc32(定义在dlgs.h中)。  此时还需要将OPENFILENAME结构中的lpfnHook成员,设置成用户定义的勾子函数,将lpTemplateName成员设置成用户定义对话框的ID值(需要用MAKEINTRESOURCE),此外,成员Flags需要设置成OFN_EXPLORER(WINDOW32中使用) OFN_ENABLEHOOK(允许使用用户定义的勾子函数) OFN_ENABLETEMPLATE(允许用户定义的对话框模板)。  现在一切就绪,剩下的工作便是着手编写这一程序,看看这动人的一幕。  以下为我设计的全部源程序。此程序在PWIN95,Borland C++5.0中通过。 //OpenFile.rh
#ifndef _OPENFILE_RH
#define _OPENFILE_RH
#define IDD_OPENFILE 100 //打开文件
#define IDM_FILEOPEN 106 //打开文件菜单命令
#define IDM_EXIT 107 //退出
#define IDE_EDIT 1022 //预展EDIT
#define ID_PRESHOW 1023 //预展CheckBox按钮
#endif
//OpenFile.h
#define STRICT
#ifdef RC_INVOKED
#include
#else
#include
#endif
#define MAX_PATH 260
long APIENTRY MainWndProc(HWND, UINT, UINT, LONG);
BOOL CALLBACK OpenFileNameDlgProc(HWND ,UINT,UINT,LONG);
BOOL InitApplication(HANDLE);
BOOL InitInstance(HANDLE, int);
void CALLBACK SetErrorMsg(HWND,UINT,const char *,char *);
BOOL OpenTheFile( OPENFILENAME *);
BOOL NEAR PASCAL TestNotify(HWND, LPOFNOTIFY);
//OpenFile.RC
#include "openfile.rh"
#include

IDD_OPENFILE DIALOG 0, 0, 251, 130
STYLE DS_3DLOOK DS_CONTROL WS_CHILD WS_VISIBLE WS_CLIPSIBLINGS
FONT 9, "MS Sans Serif"
{
LTEXT "", stc32, 4, 4, 124, 125
CONTROL "以文本方式预展", ID_PRESHOW, "button", BS_AUTOCHECKBOX WS_CHILD
WS_VISIBLE WS_TABSTOP, 132, 121, 104, 9
CONTROL "", IDE_EDIT, "edit", ES_LEFT ES_MULTILINE ES_AUTOVSCROLL
ES_AUTOHSCROLL WS_CHILD WS_VISIBLE WS_BORDER WS_TABSTOP,
132, 4, 116, 112
}
OPENFILEMENU MENU
{
POPUP "&Options"
{
MENUITEM "&File Open...", IDM_FILEOPEN
MENUITEM "E&xit", IDM_EXIT
}
}
//OpenFile.h
#include
#include
#include
#include "openfile.rh"
#include "openfile.h"
HINSTANCE g_hInst; //应用程序的实例句柄
OPENFILENAME OpenFileName; //打开文件结构
char szFile[MAX_PATH]; //文件名
#pragma argsused
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow )
{ MSG msg;
OSVERSIONINFO osVer;
osVer.dwOSVersionInfoSize = sizeof(osVer);
if (!GetVersionEx(&osVer)) //取版本信息不成功返回
return (FALSE);
if (osVer.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
{//不在Window95环境下
MessageBox(NULL, "此程序需要在Windows 95下运行.", "警告", MB_OK );
return (FALSE);
}
if (!InitApplication(hInstance)) //初始化应用程序失败
return (FALSE);
if (!InitInstance(hInstance, nCmdShow))
return (FALSE);
while (GetMessage(&msg,NULL,0,0))
{ TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (msg.wParam);
}
BOOL InitApplication(HANDLE hInstance)
{ WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = "OpenFileMenu";
wc.lpszClassName = "OpenFileNameClass";
return (RegisterClass(&wc));
}
BOOL InitInstance( HANDLE hInstance, int nCmdShow)
{ HWND hWnd;
g_hInst = hInstance; //保存当前应用程序的实例句柄
hWnd = CreateWindow(
"OpenFileNameClass",
"为你的OpenFile增加预视功能",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
g_hInst,
NULL
);
if (!hWnd) //窗口不能建立
return (FALSE);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return (TRUE);
}
LONG APIENTRY MainWndProc( HWND hWnd, UINT message, UINT wParam, LONG lParam)
{ static HWND hwndEdit;
CHAR lpszHello[] = "请从菜单上选择Open File,可看到OpenFile中的预视功能.";
switch (message) {
case WM_CREATE:
OpenFileName.lStructSize = sizeof(OPENFILENAME); //结构大小
OpenFileName.hwndOwner = hWnd;
OpenFileName.hInstance = g_hInst;
OpenFileName.lpstrFilter= "文本文件名(*.txt)\0*.TXT\0所有文件(*.*)\0*.*\0\0";
OpenFileName.lpstrCustomFilter =NULL;
OpenFileName.nMaxCustFilter = 0;
OpenFileName.nFilterIndex = 0;
OpenFileName.lpstrFile = szFile;
OpenFileName.nMaxFile = sizeof(szFile);
OpenFileName.lpstrFileTitle = NULL;
OpenFileName.nMaxFileTitle = 0;
OpenFileName.lpstrInitialDir = NULL;
OpenFileName.lpstrTitle = "打开文件"; //窗口标题
OpenFileName.nFileOffset = 0;
OpenFileName.nFileExtension = 0;
OpenFileName.lpstrDefExt = "txt"; //扩展文件名
hwndEdit = CreateWindow( //建立一编辑窗口
"EDIT", NULL,
WS_CHILD WS_VISIBLE WS_VSCROLL
ES_LEFT ES_MULTILINE ES_AUTOVSCROLL,
0, 0, 0, 0,
hWnd,
NULL,
(HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE),
NULL);
//设置信息
SendMessage(hwndEdit, WM_SETTEXT, 0, (LPARAM) lpszHello);
return 0;
case WM_SIZE:
MoveWindow(hwndEdit, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
return 0;
case WM_COMMAND:
switch( LOWORD( wParam ))
{ case IDM_FILEOPEN: //选中了打开文件菜单项
if(OpenTheFile( &OpenFileName))
SendMessage(hwndEdit, WM_SETTEXT, 0,
(LPARAM)OpenFileName.lpstrFile);
break;
case IDM_EXIT:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return (0);
}
//函数作用:打开文件
BOOL OpenTheFile(OPENFILENAME *OpenFileName)
{ OpenFileName->lCustData = NULL;
OpenFileName->lpfnHook = (LPOFNHOOKPROC) OpenFileNameDlgProc;
OpenFileName->lpTemplateName = MAKEINTRESOURCE(IDD_OPENFILE);
OpenFileName->Flags =OFN_EXPLORER OFN_HIDEREADONLY
OFN_ENABLEHOOK OFN_ENABLETEMPLATE;
return(GetOpenFileName(OpenFileName));
}
BOOL NEAR PASCAL TestNotify(HWND hDlg, LPOFNOTIFY pofn)
{ HFILE hFile; //打开文件名柄
long dwBytesRead; long dwFileSize;
LPSTR lpBuf; char szFile[MAX_PATH];
if (pofn->hdr.code!=CDN_SELCHANGE) //文件选择改变
return(FALSE);
if (SendDlgItemMessage(hDlg,ID_PRESHOW,BM_GETCHECK,0,0L)==0)
//用户没有选中预展按钮,则直接返回
return(FALSE);
if (CommDlg_OpenSave_GetSpec(GetParent(hDlg), //获取选中的文件名
szFile, sizeof(szFile)) <= sizeof(szFile))
{ hFile =_lopen((LPSTR)szFile,OF_READ);
if (hFile==HFILE_ERROR)
{SetErrorMsg(hDlg,IDE_EDIT,"文件[%s]不能开",szFile);
return FALSE; //打开文件失败失败,返回
}
dwFileSize =_llseek(hFile,0L,FILE_END); //取文件大小
if (dwFileSize == HFILE_ERROR) //失败,则返回
{ SetErrorMsg(hDlg,IDE_EDIT,"移动文件[%s]指针出错.",szFile);
_lclose(hFile); return FALSE;
}
_llseek(hFile,0L,FILE_BEGIN);
lpBuf = (char *)GlobalAlloc( GMEM_FIXED, dwFileSize );
if (lpBuf == NULL ) //分配内存失败失败
{SetErrorMsg(hDlg,IDE_EDIT,"不能为文件[%s],分配内存",szFile);
_lclose( hFile );
return FALSE;
}
dwBytesRead= _lread(hFile,(LPVOID)lpBuf, dwFileSize);
//读文件到lpBUf处
if (dwBytesRead ==HFILE_ERROR) //读文件失败
{ SetErrorMsg(hDlg,IDE_EDIT,"读文件[%s]失败",szFile);
GlobalFree(lpBuf);
_lclose( hFile );
return FALSE;
}
SetDlgItemText(hDlg,IDE_EDIT,lpBuf);
_lclose(hFile); //关闭文件
GlobalFree(lpBuf);//释放分配的内存
return TRUE;
}
else return(TRUE);
}
#pragma argsused
void CALLBACK SetErrorMsg(HWND hDlg,UINT id,const char *format,char *msg)
{ char buf[MAX_PATH];
wsprintf(buf,format,msg);
SetDlgItemText(hDlg,id,buf);
}
#pragma argsused
BOOL CALLBACK OpenFileNameDlgProc(HWND hDlg, UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{ char buf=0;
OFNOTIFY of;
switch (uMsg)
{ case WM_COMMAND: //用户在PreShow按钮上改变了显示
if(wParam==ID_PRESHOW)
{ if (!SendDlgItemMessage(hDlg,ID_PRESHOW,BM_GETCHECK,0,0L))
//没有选中,则将预展EDIT窗口设置为空
SetDlgItemText(hDlg,IDE_EDIT,&buf);
else
{of.hdr.code=CDN_SELCHANGE; //否则,调用TestNotify处理
TestNotify(hDlg,(LPOFNOTIFY)&of);
}
}
return FALSE;
case WM_NOTIFY:
 TestNotify(hDlg, (LPOFNOTIFY)lParam);
 return(TRUE);
default:
return FALSE;
}
}

通过文件路径获取文件名和扩展名 _tsplitpath

_tsplitpath
通过文件路径获取文件名和扩展名
// crt_makepath.c
#include
#include
int main( void )
{
char path_buffer[_MAX_PATH];
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_makepath( path_buffer, "c", "file:////sample//crt//", "makepath", "c" );
printf( "Path created with _makepath: %s\n\n", path_buffer );
_splitpath( path_buffer, drive, dir, fname, ext );
printf( "Path extracted with _splitpath:\n" );
printf( " Drive: %s\n", drive );
printf( " Dir: %s\n", dir );
printf( " Filename: %s\n", fname );
printf( " Ext: %s\n", ext );
}
パス名を構成要素に分解します。
void _splitpath(const char *path,char *drive,char *dir,
char *fname,char *ext );
void _wsplitpath(const wchar_t *path,wchar_t *drive,
wchar_t *dir,wchar_t *fname,wchar_t *ext );
パラメータ
path
完全パス。
drive
ドライブを表す文字 (省略可能)。後ろにコロン (:) を付けます。
dir
ディレクトリ パスと末尾のスラッシュ (省略可能)。後ろにスラッシュ (/)、円記号 (\) を付けます (混在可)。
fname
ベース ファイル名 (拡張子なし)。
ext
ファイル名の拡張子 (省略可能)。先頭にピリオド (.) が付きます。
解説-〉详见msdn

星期四, 八月 31, 2006

CListCtrl(2)

实现点击列头排序:
定义可以排序的列表类
只需要多定义两个变量
class SortCListCtrl : public CListCtrl
{
// Construction
public:
SortCListCtrl();
// Attributes
public:
BOOL m_fAsc;//是否顺序排序
int m_nSortedCol;//当前排序的列
....
}
在使用可以排序列表时 实例化自己的变量
SortCListCtrl m_yktlist;
//响应点击列函数
void CAuditingCertView::

OnColumnclickListYkt(NMHDR* pNMHDR, LRESULT* pResult)
{
for (int i = 0; i < m_yktlist.GetItemCount(); i)
{
m_yktlist.SetItemData(i, i);//供排序使用的item编号
}
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
//设置排序方式
if( pNMListView->iSubItem ==m_yktlist.m_nSortedCol )
m_yktlist.m_fAsc = !m_yktlist.m_fAsc;
else
{
m_yktlist.m_fAsc = TRUE;
m_yktlist.m_nSortedCol = pNMListView->iSubItem;
}
//调用排序函数,此函数为CListCtrl定义好的,但是需要调

用我们定义的函数才比较任意两个项目的值
m_yktlist.SortItems(MyListCompare, (LPARAM)&m_yktlist);
for ( i = 0; i < m_yktlist.GetItemCount(); i){
m_yktlist.SetItemData(i, i);//供排序使用的item编号
CString s;
s.Format("%d",i 1);//编号
m_yktlist.SetItemText(i,0,s);
}
*pResult = 0;
}
///全局函数,比较两个项目的依据
int CALLBACK MyListCompare(LPARAM lParam1,

LPARAM lParam2, LPARAM lParamSort)
{
//通过传递的参数来得到CSortList对象指针,从而得到排序方式
SortCListCtrl * pV=(SortCListCtrl *)lParamSort;
//通过ItemData来确定数据
CString szComp1,szComp2;
int iCompRes;
szComp1=pV->GetItemText(lParam1,pV->m_nSortedCol);
szComp2=pV->GetItemText(lParam2,pV->m_nSortedCol);
switch(pV->m_nSortedCol)
{
case(0):
//以第一列为根据排序 编号
iCompRes=atof(szComp1)<=atof(szComp2)?-1:1;
break;
case(4):
//以第5列为根据排序 总次数
iCompRes=atof(szComp1)<=atof(szComp2)?-1:1;
break;
default:
iCompRes=szComp1.Compare(szComp2);
break;
}
//根据当前的排序方式进行调整
if(pV->m_fAsc)
return iCompRes;
else
return -iCompRes;
}
导出数据为excel文件
使用ODBC将数据输出到excel数据区
void ExportAsExcel(CString filename,

CListCtrl &resultlist,CWnd * wnd)
{
CDatabase database;
CString sDriver = "MICROSOFT EXCEL DRIVER (*.XLS)";

// Excel安装驱动
CString sSql,sExcelFile;
//弹出对话框选择路径
CFileDialog fileDlg (FALSE, "Path", filename,

OFN_FILEMUSTEXIST OFN_HIDEREADONLY, "*.xls",wnd);
if( fileDlg.DoModal()==IDOK)
{
sExcelFile = fileDlg.GetPathName(); // 要建立的Excel文件
CFileFind finder;
BOOL bWorking = finder.FindFile(sExcelFile);//寻找文件
if (bWorking)//如果已经存在文件,则删除
{
CFile::Remove((LPCTSTR)sExcelFile);
}
}
else return;
TRY
{
// 创建进行存取的字符串
sSql.Format("DRIVER={%s};

DSN='';FIRSTROWHASNAMES=1;READONLY=FALSE;
CREATE_DB=\"%s\";DBQ=%s",sDriver, sExcelFile, sExcelFile);
// 创建数据库 (既Excel表格文件) if( database.OpenEx(sSql,

CDatabase::noOdbcDialog) )
{
CHeaderCtrl* pHeader = resultlist.GetHeaderCtrl();
//获得行,列的个数
int nColCount = pHeader->GetItemCount();
int nLineCount = resultlist.GetItemCount();
int ColOrderArray[100];
CString ca[100];
resultlist.GetColumnOrderArray(ColOrderArray, nColCount);
//检索各列的信息,确定列标题的内容
for(int i =0 ; i< nColCount; i )
{
LVCOLUMN lvc;
char text[100];
lvc.mask = LVCF_TEXTLVCF_SUBITEM;
lvc.pszText = text;
lvc.cchTextMax = 100;
resultlist.GetColumn(ColOrderArray[i], &lvc);
ca[i] = lvc.pszText;
}
// 创建表结构
CString tempsql="(";
for(i =0 ; i< nColCount-1; i )
{
tempsql =ca[i];
tempsql =" TEXT,";
}
tempsql =ca[nColCount-1];
tempsql =" TEXT)";
sSql = "CREATE TABLE Sheet1 ";
sSql =tempsql;
database.ExecuteSQL(sSql);
//插入数据
int item_count=resultlist.GetItemCount();
tempsql="(";
for(i =0 ; i< nColCount-1; i )
{
tempsql =ca[i];
tempsql =" ,";
}
tempsql =ca[nColCount-1];
tempsql =")";
for(int itemnum=0;itemnum<item_count;itemnum ){
sSql="";
sSql ="INSERT INTO Sheet1 ";
sSql =tempsql;
sSql ="VALUES ('";
for(i =0 ; i< nColCount-1; i )
{
sSql =resultlist.GetItemText(itemnum, i);
sSql ="','";
}
sSql =resultlist.GetItemText(itemnum, nColCount-1);
sSql ="')";
database.ExecuteSQL(sSql);
}
}
// 关闭数据库
database.Close();
AfxMessageBox("Excel文件写入成功!");
}
CATCH_ALL(e)
{
TRACE1("Excel驱动没有安装: %s",sDriver);
}
END_CATCH_ALL;
}

CListCtrl 使用心得

CListCtrl 使用心得
初始化:
DWORD dwStyle;
dwStyle = m_bzlist.GetStyle();
dwStyle = LVS_EX_GRIDLINES LVS_EX_FULLROWSELECTLVS_SHOWSELALWAYS ;
m_bzlist.SetExtendedStyle(dwStyle);
m_bzlist.SetBkColor(RGB(0xec,0xf1,0xfd));
m_bzlist.SetTextBkColor(RGB(0xfe,0xFF,0xc6));

插入一列:
m_bzlist.InsertColumn(0,"编号");
m_bzlist.SetColumnWidth(0,50);

插入一行: 方法1:
LV_ITEM lvitem; lvitem.pszText="";
lvitem.mask=LVIF_TEXT;
lvitem.iSubItem=0;
lvitem.iItem=0;
m_jbxxlist.InsertItem(&lvitem);
m_jbxxlist.SetItemText(0,0,xh);
m_jbxxlist.SetItemText(0,1,xm);
m_jbxxlist.SetItemText(0,2,nj);

方法2:
m_yktlist.InsertItem(i,"2");
m_yktlist.SetItemText(i,0,s);
m_yktlist.SetItemText(i,1,xh);
m_yktlist.SetItemText(i,2,xm);

读取数据:
resultlist.GetItemText(行数, 列数);

每行前有复选框的列表:
初始化时使用LVS_EX_CHECKBOXES属性
DWORD dwStyle;
dwStyle = m_yktlist.GetStyle();
dwStyle = LVS_EX_GRIDLINES LVS_EX_FULLROWSELECTLVS_EX_CHECKBOXES ;
m_yktlist.SetExtendedStyle(dwStyle);

设置选中:
m_yktlist.SetItemState (行数,LVIS_SELECTED, LVIS_SELECTED);//设为选中状态
m_yktlist.SetCheck(行数,true/false);

判断是否选中:
m_yktlist.GetItemState(行数,LVIS_SELECTED)==LVIS_SELECTED//选中
m_yktlist.GetCheck(行数)

选中当前选中的 Item :
POSITION pos = mListDvdInfo.GetFirstSelectedItemPosition();
while(pos != NULL){ int nIndex = mListDvdInfo.GetNextSelectedItem(pos); } Item

改变的消息相应:
LVN_ITEMCHANGED LVN_ITEMCHANGING

在ListCtrl中进行排序

在ListCtrl中进行排序
列表控件(CListCtrl)的顶部有一排按钮,用户可以通过选择不同的列来对记录进行排序。但是 CListCtrl并没有自动排序的功能,我们需要自己添加一个用于排序的回调函数来比较两个数据的大小,此外还需要响应排序按钮被点击的消息。下面讲述一下具体的做法。

CListCtrl提供了用于排序的函数,函数原型为:BOOL CListCtrl::SortItems( PFNLVCOMPARE pfnCompare, DWORD dwData )。其中第一个参数为全局排序函数的地址,第二个参数为用户数据,你可以根据你的需要传递一个数据或是指针。该函数返回-1代表第一项排应在第二项前面,返回1代表第一项排应在第二项后面,返回0代表两项相等。

用于排序的函数原形为:int CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort),其中第三个参数为调用者传递的数据(即调用SortItems时的第二个参数dwData)。第一和第二个参数为用于比较的两项的ItemData,你可以通过DWORD CListCtrl::GetItemData( int nItem )/BOOL CListCtrl::SetItemData( int nItem, DWORD dwData )来对每一项的ItemData进行存取。在添加项时选用特定的CListCtrl::InsertItem也可以设置该值。由于你在排序时只能通过该值来确定项的位置所以你应该比较明确的确定该值的含义。

最后一点,我们需要知道什么时候需要排序,实现这点可以在父窗口中对LVN_COLUMNCLICK消息进行处理来实现。

下面我们看一个例子,这个例子是一个派生类,并支持顺序/倒序两种方式排序。为了简单我对全局数据进行排序,而在实际应用中会有多组需要排序的数据,所以需要通过传递参数的方式来告诉派序函数需要对什么数据进行排序。


//全局数据
struct DEMO_DATA
{
char szName[20];
int iAge;
}strAllData[5]={{"王某",30},{"张某",40},{"武某",32},{"陈某",20},{"李某",36}};

//CListCtrl派生类定义
class CSortList : public CListCtrl
{
// Construction
public:
CSortList();
BOOL m_fAsc;//是否顺序排序
int m_nSortedCol;//当前排序的列
protected:
//{{AFX_MSG(CSortList)
//}}AFX_MSG
...
};

//父窗口中包含该CListCtrl派生类对象
class CSort_in_list_ctrlDlg : public CDialog
{
// Construction
public:
CSort_in_list_ctrlDlg(CWnd* pParent = NULL); // standard constructor

// Dialog Data
//{{AFX_DATA(CSort_in_list_ctrlDlg)
enum { IDD = IDD_SORT_IN_LIST_CTRL_DIALOG };
CSortList m_listTest;
//}}AFX_DATA
}

//在父窗口中定义LVN_COLUMNCLICK消息映射
BEGIN_MESSAGE_MAP(CSort_in_list_ctrlDlg, CDialog)
//{{AFX_MSG_MAP(CSort_in_list_ctrlDlg)
ON_NOTIFY(LVN_COLUMNCLICK, IDC_LIST1, OnColumnclickList1)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

//初始化数据
BOOL CSort_in_list_ctrlDlg::OnInitDialog()
{
CDialog::OnInitDialog();

//初始化ListCtrl中数据列表
m_listTest.InsertColumn(0,"姓名");
m_listTest.InsertColumn(1,"年龄");
m_listTest.SetColumnWidth(0,80);
m_listTest.SetColumnWidth(1,80);
for(int i=0;i<5;i++)
{
m_listTest.InsertItem(i,strAllData[i].szName);
char szAge[10];
sprintf(szAge,"%d",strAllData[i].iAge);
m_listTest.SetItemText(i,1,szAge);
//设置每项的ItemData为数组中数据的索引
//在排序函数中通过该ItemData来确定数据
m_listTest.SetItemData(i,i);
}
return TRUE; // return TRUE unless you set the focus to a control
}

//处理消息
void CSort_in_list_ctrlDlg::OnColumnclickList1(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
//设置排序方式
if( pNMListView->iSubItem == m_listTest.m_nSortedCol )
m_listTest.m_fAsc = !m_listTest.m_fAsc;
else
{
m_listTest.m_fAsc = TRUE;
m_listTest.m_nSortedCol = pNMListView->iSubItem;
}
//调用排序函数
m_listTest.SortItems( ListCompare, (DWORD)&m_listTest );
*pResult = 0;
}

//排序函数实现
int CALLBACK ListCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
//通过传递的参数来得到CSortList对象指针,从而得到排序方式
CSortList* pV=(CSortList*)lParamSort;

//通过ItemData来确定数据
DEMO_DATA* pInfo1=strAllData+lParam1;
DEMO_DATA* pInfo2=strAllData+lParam2;
CString szComp1,szComp2;
int iCompRes;
switch(pV->m_nSortedCol)
{
case(0):
//以第一列为根据排序
szComp1=pInfo1->szName;
szComp2=pInfo2->szName;
iCompRes=szComp1.Compare(szComp2);
break;
case(1):
//以第二列为根据排序
if(pInfo1->iAge == pInfo2->iAge)
iCompRes = 0;
else
iCompRes=(pInfo1->iAge < pInfo2->iAge)?-1:1;
break;
default:
ASSERT(0);
break;
}
//根据当前的排序方式进行调整
if(pV->m_fAsc)
return iCompRes;
else
return iCompRes*-1;
}

排序最快:
CListCtrl::SortItems
Example

// Sort the item in reverse alphabetical order.
static int CALLBACK
MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
// lParamSort contains a pointer to the list view control.
// The lParam of an item is just its index.
CListCtrl* pListCtrl = (CListCtrl*) lParamSort;
CString strItem1 = pListCtrl->GetItemText(lParam1, 0);
CString strItem2 = pListCtrl->GetItemText(lParam2, 0);

return strcmp(strItem2, strItem1);
}

void snip_CListCtrl_SortItems()
{
// The pointer to my list view control.
extern CListCtrl* pmyListCtrl;

// Sort the list view items using my callback procedure.
pmyListCtrl->SortItems(MyCompareProc, (LPARAM) pmyListCtrl);
}

星期三, 八月 30, 2006

ビットマップボタン

WTLでは標準コントロールやコモンコントロールの他に、独自のコントロール用クラスを用意しています。

 ビットマップボタンは、ビットマップ画像からボタンの外観を作成できるボタンコントロールです。 WTLはビットマップボタンを作成するためにCBitmapButtonというクラスを用意しています。 MFCにも同名のクラスがありますが、それとは使用方法が異なります。

CBitmapButtonクラスはCButtonクラスから派生しています。以下に示すのは、CBitmapButtonクラスを使用する例です。下の図のような白いボタンを作成します。


// stdafx.h内 
#include <atlbase.h> 
#include <atlapp.h> 
extern CAppModule _Module; 
#include <atlwin.h>  
#include <atlcrack.h> 
#include <atlmisc.h> 
#include <atlctrls.h> 
#include <atlctrlx.h>  
// CBitmapButtonクラスを使用するため    

// maindlg.h内 
class CMainDlg : public CDialogImpl<CMainDlg> 
{ 
public:     
enum { IDD = IDD_MAINDLG };      
CBitmapButton m_button_bmp;     // ビットマップボタン      
// メッセージマップ     
BEGIN_MSG_MAP_EX(CMainDlg)         
MSG_WM_INITDIALOG(OnInitDialog)         
COMMAND_ID_HANDLER_EX(IDC_BUTTON_BMP, OnButtonBmp)         
COMMAND_ID_HANDLER_EX(IDOK, OnOK)         
COMMAND_ID_HANDLER_EX(IDCANCEL, OnCancel)     
END_MSG_MAP()      
 
LRESULT OnInitDialog(HWND hWnd, LPARAM lParam){         
// スクリーンの中央に配置         
CenterWindow();          
// 大きいアイコン設定         
HICON hIcon = AtlLoadIconImage(IDR_MAINFRAME, LR_DEFAULTCOLOR,             
                                   ::GetSystemMetrics(SM_CXICON), 
                                   ::GetSystemMetrics(SM_CYICON));         
SetIcon(hIcon, TRUE);                  
// 小さいアイコン設定         
HICON hIconSmall = AtlLoadIconImage(IDR_MAINFRAME, LR_DEFAULTCOLOR,             
                                   ::GetSystemMetrics(SM_CXSMICON), 
                                   ::GetSystemMetrics(SM_CYSMICON));         
SetIcon(hIconSmall, FALSE);          // コントロール設定         
CImageList il;         
il.CreateFromImage(IDB_BITMAP_BUTTON, 64, 1,             
CLR_NONE, IMAGE_BITMAP, LR_CREATEDIBSECTION);          
m_button_bmp.SubclassWindow(GetDlgItem(IDC_BUTTON_BMP));         
m_button_bmp.SetImageList(il);         
m_button_bmp.SetImages(0, 1, 2, 3);         
m_button_bmp.SetToolTipText(_T("ビットマップボタン"));         
m_button_bmp.CenterWindow();          
return TRUE;     }      
 
void OnButtonBmp(UINT uNotifyCode, int nID, HWND hWndCtl){         
MessageBox(_T("これはビットマップボタンです。"));     
}      
 
void OnOK(UINT uNotifyCode, int nID, HWND hWndCtl){         
EndDialog(nID);     
}      
 
void OnCancel(UINT uNotifyCode, int nID, HWND hWndCtl){         
EndDialog(nID);     
} };    

// Control.cpp内 
#include "stdafx.h"  
#include "resource.h"  
#include "maindlg.h"  
CAppModule _Module;  
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE, 
                    LPTSTR lpCmdLine, int nCmdShow) {     
HRESULT hRes = ::CoInitialize(NULL);     
ATLASSERT(SUCCEEDED(hRes));      
::DefWindowProc(NULL, 0, 0, 0L);      
AtlInitCommonControls(ICC_COOL_CLASSES  ICC_WIN95_CLASSES);      
hRes = _Module.Init(NULL, hInstance);     
ATLASSERT(SUCCEEDED(hRes));      
int nRet = 0;     // BLOCK: アプリケーション実行     {         
CMainDlg dlgMain;         
nRet = dlgMain.DoModal();     }      
_Module.Term();     
::CoUninitialize();      
return nRet; }    

 まず、リソースを作成します。ダイアログにボタンコントロールを配置し、リソースIDを次のように指定します。

コントロール名リソースID
プッシュボタンIDC_BUTTON_BMP

また、プロジェクトに次のようなビットマップリソースをIDB_BITMAP_BUTTONというIDで追加します。



このビットマップは、ボタンの4つの状態(通常の状態、押された状態、フォーカスが当たっている状態、使用不可の状態)を表す一つの画像です。

 次に、stdafx.h内では、CBitmapButtonクラスを使用するためにatlctrls.hヘッダとatlctrlx.hヘッダをインクルードします。なお、atlctrls.hヘッダを先にインクルードする必要があります。

 CMainDlgクラスでは、まず、 CBitmapButtonクラスのインスタンスをメンバ変数として宣言します。これを使うためには、WM_INITDIALOGメッセージハンドラでサブクラス化する必要があります。

 次に、WM_INITDIALOGメッセージハンドラでは、ビットマップリソース(ID:IDB_BITMAP_BUTTON)からイメージリストを作成し、それをSetImageList()によってビットマップボタンに設定します。イメージリストを設定した後は、SetImages()によってイメージリストのインデックスとボタンの状態を関連付けます。 SetImages()は、第1引数から順に、通常の状態、押された状態、フォーカスが当たった状態、使用不可の状態のイメージリストのインデックスを受け取ります。さらに、ビットマップボタンには、SetToolTipText()によってツールチップを設定しています。

 最後に、リソースIDがIDC_BUTTON_BMPのコマンドメッセージハンドラとして、 OnButtonBmp()を追加します。このハンドラでは単にメッセージボックスを表示しているだけです。

 このように、MFCのビットマップボタンではボタンの状態別の4つビットマップリソースを用意しなければならないのに対し、 WTLのビットマップボタンはイメージリストからボタンの外観を作成します。

 WTLのビットマップボタンは、独自の拡張スタイルを用意しています。

  • BMPBTN_HOVER
    マウスカーソルがビットマップボタンの上を通ると、フォーカスが当たった状態の画像を表示します。

  • BMPBTN_AUTO3D_SINGLE
    画像の周りに3Dの境界線を描画します。

  • BMPBTN_AUTO3D_DOUBLE
    BMPBTN_AUTO3D_SINGLEよりも少し太い境界線を描画します。

  • BMPBTN_AUTOSIZE
    画像の大きさに合うようにビットマップボタンのサイズを自動的に変更します。このスタイルはデフォルトで設定されています。

  • BMPBTN_SHAREIMAGELISTS
    ビットマップボタンのオブジェクトが破棄されても、ビットマップボタンに設定されたイメージリストのオブジェクトは破棄しません。

  • BMPBTN_AUTOFIRE
    ビットマップボタンを押し続けると、繰り返しWM_COMMANDメッセージを発生させます。

これらの拡張スタイルは、SetBitmapButtonExtendedStyle()によって設定します。

CBitmapButton のツールチップ (CTalkButton クラス)

CTalkButton クラスについて CFolderDialog に続いて
作った2つ目のオリジナルの クラスだ。 できればこんな遠
回りは したくなかったが、結果的に大仕事になってしまった。
(前と同じじゃん。) 原因は VC++環境のツールバーに
ある。大きさは変えられるものの 色が16色しか使えない。
いまどきこんな色数じゃボタンの機能を表すにあたって著
しく 表現の幅を狭められてしまう。  アイコンも最初は16
色になっているので酩酊してしまうが、後で256色に変更
できる ので、 まあよしとしよう。(最初から256色だとな
およいが。 自作のアプリケーションで 16色アイコンなん
ぞ使ったことがない。)せっかくツールバー 用にと画像を用
意したのに16色に落とすと何がなんだか分からなくなって
しまった。 努力を無にしたくなかったのでビットマップボタン
を並べてツールバーに 見せたが、 ツールチップが出ない
ところや、 ステータスバーの表示もないところがいかにも
自作という感じだ。 で、自作のツールバーにツールチップ
ステータスバーの表示機能を持たせようという試みが
泥沼化しこのクラスになった。 本当は CDialogBar を
使いたかったがダイアログエディタで乗っけた CButton
に BS_ BITMAP でもってビットマップを貼り付けるのがど
うしてもうまくいかず、そのうちに CTalkButtonクラスの
方が何とか形になったので途中であきらめてしまった。
CButton の BS_BITMAP を使いこなす方法はだい
ぶ後になってら分かった。ついでにツールチップのテキス
トの入れ も。でも CReBar が使いこなせた方がプロっぽ
いかも?)class CTalkButton CBitmapButton をその
まま使ってたんではどうしてもツールチップやステータスバー
の表 示が うまくできなかった。なのでこのクラスは
CBitmapButton を継承し機能拡張を行っている。
#if !defined(AFX_TALKBUTTON_H__1DC177F6
_3055_45D1_9E99_0B07854838C4__INCLUDED_)

#define AFX_TALKBUTTON_H__1DC177F6_

3055_45D1_9E99_0B07854838C4__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// TalkButton.h : ヘッダー ファイル
//
///////////////////////////////////////////////////
// CTalkButton ウィンドウ
class CTalkButton : public CBitmapButton
{
// コンストラクション
public:
CTalkButton();
// アトリビュート
public:
// オペレーション
public:
// オーバーライド
// ClassWizard は仮想関数のオーバーライドを生成します。
//{{AFX_VIRTUAL(CTalkButton)
public:
virtual BOOL PreTranslateMessage(MSG* pMsg);
//}}AFX_VIRTUAL
// インプリメンテーション
public:
CToolTipCtrl ttc;
virtual ~CTalkButton();
// 生成されたメッセージ マップ関数
protected:
//{{AFX_MSG(CTalkButton)
afx_msg void

OnMouseMove(UINT nFlags, CPoint point);

afx_msg int
OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnTimer(UINT nIDEvent);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ は前行の直前に追加の宣言
//を挿入します。
#endif // !defined(AFX_TALKBUTTON_H__
1DC177F6_3055_45D1_9E99_0B07854838C4
__INCLUDED_)

使用法 CBitmapButton に対して追加したメンバ関数
はハンドラだけなので使用方法は CBitmapButton と
同じ。
いつも View のメンバに入れて OnCreate() の
中で Create する方法でしか使っていないので 違う使い
方をしたときにどうなるかは分からない。
CRect rect_hlp(0, 0, 32, 32);
helpButton.Create("",

BS_OWNERDRAW BS_PUSHBUTTON
WS_CHILD WS_VISIBLE, rect_hlp, this,
ID_ABOUT);
helpButton.LoadBitmaps(IDB_HLP_FREE,

IDB_HLP_PUSH, IDB_HLP_FREE, IDB_HLP_PUSH);
 ↑ な感じでいつも使っている。各パラメータの意味は

CBitmapButton を参照。// TalkButton.cpp :
インプリメンテーション ファイル
//
#include "stdafx.h"
#include "TalkButton.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
////////////////////////////////////////////////
// CTalkButton
CTalkButton::CTalkButton()
{
}
CTalkButton::~CTalkButton()
{
}
BEGIN_MESSAGE_MAP(CTalkButton,

CButton)
//{{AFX_MSG_MAP(CTalkButton)
ON_WM_MOUSEMOVE()
ON_WM_CREATE()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
///////////////////////////////////////////////
// CTalkButton メッセージ ハンドラ
// ツールチップとステータスバーにツールヒントを出

せるビットマップボタン
int CTalkButton::OnCreate(LPCREATESTRUCT

lpCreateStruct)
{
if (CButton::OnCreate(lpCreateStruct) == -1)
return -1;
ttc.Create(this); // 以下ツールチップの作成・登録
ttc.Activate(TRUE);
CRect rect;
CWnd::GetClientRect(&rect);
ttc.AddTool(this, (UINT)GetDlgCtrlID(), &rect,

(UINT)GetDlgCtrlID());
return 0;
}
BOOL CTalkButton::PreTranslateMessage(

MSG* pMsg)
{
// ツールチップのおきまり
if (m_hWnd)
ttc.RelayEvent(pMsg);
return CButton::PreTranslateMessage(pMsg);
}
void CTalkButton::OnMouseMove(UINT nFlags,

CPoint point)
{
// 親ウインドウのステータスバーにツールヒントを表示する。
if (GetCapture() == this) {
CRect rect;
CWnd::GetClientRect(&rect);
if (!rect.PtInRect(point)) { // マウスがボタンの外

に出たときに idle を出したいから
KillTimer(999); // 自分の上にいるときだけキャ
プチャしてるんだよ。
ReleaseCapture(); // どんくさいだろ。
GetParent()->GetParentFrame()->

SetMessageText(AFX_IDS_IDLEMESSAGE);
}
} else {
GetParent()->GetParentFrame()->

SetMessageText((UINT)GetDlgCtrlID());
SetCapture();
SetTimer(999, 200, NULL); // 親ウインドウ監視タイマー
}
// 自作のツールバーにツールチップを出そうとしてえらい苦労した。
// あんまりうまくいかないんで、あきらめてステータスバーの表示に
// 変更したがそれでも大変だった。
// この CTalkButton を CBitmapButton から派生させることで
// 乗り切ったが、あとでツールチップも実装した。
// 結局、派生クラスを作るんだったらツールチップのほうが楽だった。
// 親ウインドウがバックグラウンドになったときにステータスバーを
// idle に戻したかったのでまたタイマーに頼ってしまった。
CButton::OnMouseMove(nFlags, point);
}
void CTalkButton::OnTimer(UINT nIDEvent)
{
// 親ウインドウがバックグラウンドになったときは

キャプチャーをやめる
if (GetForegroundWindow() != GetParent()->

GetParentFrame()) {
KillTimer(999); // またタイマー使っちゃったよ。
ReleaseCapture(); // もっといいメッセージないの?
GetParent()->GetParentFrame()->

SetMessageText(AFX_IDS_IDLEMESSAGE);
}
CButton::OnTimer(nIDEvent);
}




星期二, 八月 29, 2006

玩转keybd_event(转载)

玩转keybd_event

模拟键盘平时不是很常用, 但是当调用某些快捷键执行某项功能时, 它真的是那么的方便呀. 你不信? 看看下面的实现, 你就会大呼: 为什么不早点告诉我? 呵呵, 原来没有blog呀, 都靠这些挣分呢.

1) 显示桌面:

很多软件有显示桌面的功能, 并且大家的方法都是遍历窗口, 然后让它们最小化, 其实 win系统给咱们了一个非常方便的WIN键(就是键盘上在CTRL键和ALT键之间的那个带win标志的按键), 利用它, 可以轻松的完成显示桌面的功能.

keybd_event(VK_LWIN, 0, 0 ,0);
keybd_event('M', 0, 0 ,0);
keybd_event('M', 0, KEYEVENTF_KEYUP ,0);
keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP,0);

其他的操作也类似, 比如直接显示开始的运行,就把上面的'M'换成'R'即可。

直接 keybd_event(VK_LWIN, 0, 0 ,0);
keybd_event(VK_LWIN, 0, KEYEVENTF_KEYUP,0);

直接显示“开始”对话框了。

2) 实现快速的全选

很多的时候,比如listctrl实现全选,你可以用listctrl循环设置每一项的状态为选中,多罗索的事情呀。用快捷键试一试CTRL+A,其他的快捷键一样的用法,呵呵,你知道怎么办了吧?

keybd_event(VK_CONTROL, (BYTE)0, 0 ,0);
keybd_event('A',(BYTE)0, 0 ,0); //此处可以用 'A', (BYTE)65, 用'a'不起作用.
keybd_event('A', (BYTE)0, KEYEVENTF_KEYUP,0);
keybd_event(VK_CONTROL, (BYTE)0, KEYEVENTF_KEYUP,0);

3) 执行某些特殊的键,比如数字键,大小写,下面是数字键的例子

bool bState=true; //true为按下NumLock,false反之
BYTE keyState[256];

GetKeyboardState((LPBYTE)&keyState);
if( (bState && !(keyState[VK_NUMLOCK] & 1))
(!bState && (keyState[VK_NUMLOCK] & 1)) )
{
// Simulate a key press
keybd_event( VK_NUMLOCK,
0x45,
KEYEVENTF_EXTENDEDKEY 0,
0 );

// Simulate a key release
keybd_event( VK_NUMLOCK,
0x45,
KEYEVENTF_EXTENDEDKEY KEYEVENTF_KEYUP,
0);
}

4) 你想CTRL+ALT+DELETE三键一起按下,

keybd_event(VK_CONTROL, 0, 0 ,0);
keybd_event(VK_MENU,0, 0 ,0);
keybd_event(VK_DELETE,0, 0 ,0);

keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP ,0);
keybd_event(VK_MENU,0, KEYEVENTF_KEYUP ,0);
keybd_event(VK_DELETE,0, KEYEVENTF_KEYUP ,0);
呵呵,这样不会成功呀,因为这几个键直接是操作系统来截获执行的,而模拟键盘只能发向应用程序,所以这种方法不行的(想显示锁定对话框,用 LockWorkStation();)

5) Window2000/NT/XP已经不提倡用这个函数了,上面的方法只是为了让大家开阔一下思路,怎么替代呢,呵呵,看下面,所以上面的所有代码都可以用这个来完成

//2000下用这个代替 ,包含 "winable.h"
INPUT input[4];
memset(input, 0, sizeof(input));

input[0].type = input[1].type = input[2].type = input[3].type = INPUT_KEYBOARD;

input[0].ki.wVk = input[3].ki.wVk = VK_LWIN;
input[1].ki.wVk = input[2].ki.wVk = 'R';


//接下来释放它,这一点很重要。
input[2].ki.dwFlags = input[3].ki.dwFlags = KEYEVENTF_KEYUP;
input[0].ki.time = input[1].ki.time = input[2].ki.time = input[3].ki.time = GetTickCount();

SendInput(4, input, sizeof(INPUT));

感觉比那个有点罗索,呵呵。

====================

附WIN键的部分快捷键:

WIN键+D=快速的切到桌面,再次点击返回

WIN键+E=快速打开资源管理器

WIN键+R=“运行”。

WIN键+M=全部视窗最小化。

WIN键+Shift+M=取消全部视窗最小化。

WIN键+F1=Help。

WIN键+F=“寻找”。

WIN键+Ctrl+F=显示“查找电脑”。

WIN键+Tab=切换工作列的程式。

WIN键+Break=显示系统内容。

星期二, 八月 15, 2006

获取当前路径

GetCurrentDirectory只是获取当前的目录,当计算机重新启动后,当前的路径一般为系统目录,因此系统启动后,使用该函数只能获取当前的目录,而不是应用程序所在的目录。

使用GetModuleFileName函数,GetModuleFileName()是一个得到路径的API函数。本函数将这个API函数封装在其中,为的是简化调用的目的。

当执行这个函数时,返回本程序所在的绝对路径,包括本程序的文件名。 具体使用方法为:

//获取主程序所在路径,存在sPath中

CString sPath;

GetModuleFileName(NULL,sPath.GetBufferSetLength (MAX_PATH+1),MAX_PATH);

sPath.ReleaseBuffer ();

int nPos;

nPos=sPath.ReverseFind (’’\\’’);

sPath=sPath.Left (nPos);



星期三, 八月 02, 2006

「Windows界面」ツールチップを表示

用法
①、メンバー変数を追加(CToolTipCtrl m_tip)。
    private: CToolTipCtrl m_tip;

②、ダイアローグクラスのOnInitDialog()関数で以下の記述を追加
    EnableToolTips(TRUE); // ツールチップ利用可
    m_tip.Create(this); // コントロールを作成する
    m_tip.AddTool((CButton *)GetDlgItem(IDC_BUTTON1), "This is button"); // ツール ヒント コントロールにツールを登録します。

③、ダイアログクラスのPreTranslateMessage関数内でRelayEvent()を呼び出す
    m_tip.RelayEvent(pMsg)。

星期二, 八月 01, 2006

「Windows界面」解像度

GetDeviceCaps() は、ディスプレイの DPI を取得するために使用できます

星期五, 七月 21, 2006

关于Jsp中的Application对象

ServletContext
ServletContext是定义在javax.servlet包中的对象。它定义了用于WEB应用中的服务器端组件关联servlet容器的方法集合。
ServletContext经常被用于存储对象的区域,这些对象在WEB应用中的所有的服务器端组件中使用。你可以把ServletContext当作在WEB应用中共享的存储区域。把一个对象放置到ServletContext中时,它存在于WEB应用的整个生命周期中,除非它被明确的删除或替换。在ServletContext中定义了四个方法来实现存储区的共享功能。
表2.1描述了四个方法:
方法名
描述
setAttribute(String name,Object obj)
通过名称绑定一个对象并存储对象到当前ServletContext。如果指定的名称已经被使用过,这个方法会删除旧对象绑定为新对象。
getAttribute(String name)
返回指定名称的对象,如果名称不存在返回null。
removeAttribute(String name)
从ServletContext中删除指定名称的对象

getAttributeNames()

返回在ServletContext中的指定名称的对象集合

而ServletContext在jsp中所对应的就是application, application为ServletContext的一个引用

示例:
Servlet中
// 获取ServletContext
ServletContext context = getServletContext();
// 获取
String userName = (String)context.getAttribute("USERNAME");

在对应的Jsp中
String userName = (String)application.getAttribute("USERNAME");

Windowsサービスの起動と停止

net start "サービス名"
net stop "サービス名"