2005年10月31日

  一直想给自己的网站添加一些新比较流行的元素,比如加一个Web Menu(就像微软的网站上使用的那种风格,可以参看www.microsoft.com)来为客户的浏览提供导航功能,而且也显得比较专业。我想这无非是一些客户端的代码,客户端的功能实现,当然首选JavaScript。虽然以前我也做过自己的网站,但是JavaScript自己却不是很熟,所以想在网站上找一些代码来实现。几经搜索,找到一些ASP.net控件,下下来一看,js文件应该是使用混淆器处理过了,看不出个所以然。再看看微软的网页源码,只是链接到后台的js文件,看不到js文件的内容。最后还是下定决心自己动手来实现吧。

      要实现客户端的功能,看来JavaScript语言是绕不过了。花了3天时间在网上找了一些JavaScript的资料并且找到《JavaScript圣经》大概通读一遍。心中对我要做的东西有了个模糊的轮廓,先来看看要实现的功能:

  • 当鼠标移动到菜单项上要高亮显示菜单项。
  • 当鼠标移动到有子菜单的菜单项上时应该弹出子菜单。
  • 菜单的内容应该可以配置,用XML来保存。
  • 当鼠标在子菜单上移动时应该标识出子菜单的父菜单项。
  • 当用户点击到菜单项的时候,应响应用户的行为定位到相应的页面。

     再看看用什么样的HTML元素来表示菜单,使用Div,Span,Table还是用UR?因为我是做竖版的Menu,所以就不用Span了,因为Span是不换行的-做横版的Menu就可以用Span:)。用Table的话,太不灵活,还要管理Table本身的一些元素。用UR的话,没有子菜单倒是很简单也很方便,不过就不适合用于做带子菜单的Menu了。

    要实现Web Menu的显示,样式表是必不可免了。现看看需要用到的核心的样式表元素:

  • 首先是确定Menu的显示位置以及尺寸,是用static,relative还是absolute。absolute是用不成了,除非你的网站全不都是使用Absolute方式,这样用起来可能会好一些,relative是基于父元素计算偏移量,最后的选择是使用默认的static,这样适用性也比较强。
  • 下来是考虑子菜单的显示和隐藏。使用visibility呢还是使用display。visibility虽然会隐藏子菜单但是它依然会占用网页的空间,但是display就不会,它应该是真正的隐藏,所以使用display。

    子菜单显示在什么地方是一个很关键的问题。DHTML提供了一大堆的最表属性,看得让人头晕,不过最后还是使用OffsetParent得offset族得坐标来确定子菜单得具体位置,这样得话要写一个递归函数来获得具体得坐标。我们可以从下图看到Web元素得各种坐标:

    可以通过递归计算当前元素得父元素得offsetLeft属性计算出当前元素应显示得left坐标:

function getAscendingLefts(elem)
{
 if (elem==null)
  return 0;
 else
 {
  if (elem.style.position=='absolute' || elem.style.position=='relative') return 0;
  return elem.offsetLeft+getAscendingLefts(elem.offsetParent);
 }
}

   同理也可一写出计算Top坐标得函数:

function getAscendingTops(elem)
{
 if (elem==null)
  return 0;
 else
 {
  if ((elem.style.position=='absolute' || elem.style.position=='relative')) return 0;
  return elem.offsetTop+getAscendingTops(elem.offsetParent);
 }
}

posted @ 2005-10-31 22:02 纶巾客 阅读(234) 评论(0) 编辑
CRegKey类来操作注册表是非常方便的。CRegKey类并不是一个MFC类,而是一个ATL类,所以在使用的时候不要忘记在StdAfx.h头文件中加入#include <atlbase.h>

 
 
1.打开需要查询注册表键:

原型是:LONG Open( HKEY hKeyParent, LPCTSTR lpszKeyName, REGSAM samDesired = KEY_ALL_ACCESS );

只有打开了一个注册表键才能对其值进行操作。

hKeyParent:打开的键的句柄。

lpszKeyName:键所在的注册表的路径。   

samDesired:注册表访问的安全性。

例子:

       CRegKey rk;

       LPCTSTR lp="Software\\Compupacific\\NewEn\\AddIns\\AddButton";

if(rk.Open(HKEY_CURRENT_USER,lp)== ERROR_SUCCESS)

{

        AfxMessageBox(“Successful!”0);

}

2.获取注册表中某一键的键值:

    LONG QueryValue( DWORD& dwValue, LPCTSTR lpszValueName );

LONG QueryValue( LPTSTR szValue, LPCTSTR lpszValueName, DWORD* pdwCount )

有两个函数,第一个是查询整型值,第二个是查询字符串类型的值。下面分别对它们进行举例:

//取整型值

       CRegKey rk;

       DWORD dValue ;

      

       LPCTSTR lp="Software\\Compupacific\\NewEn\\AddIns\\AddButton";

       if(rk.Open(HKEY_CURRENT_USER,lp)== ERROR_SUCCESS)

       {

              if(rk.QueryValue( dValue,"LoadBehavior")==ERROR_SUCCESS)

              {

                     CString temp;

                     temp.Format("%d",dValue);

                     SetDlgItemText(IDC_EDIT1,temp);

              }

              else

              {

                     AfxMessageBox("Query Error");

              }

       }

       else

       {

              AfxMessageBox("Open error!");

       }

rk.Close();

//取字符串类型的值

CRegKey rk;

       HKEY m_hKey;

       DWORD pCount=1024;

       CString KeyValue;

       char szValue[1024];

 
 
       LPCTSTR lp="Software\\Compupacific\\NewEn\\AddIns\\AddButton";

       if(rk.Open(HKEY_CURRENT_USER,lp)== ERROR_SUCCESS)

       {

              LPCTSTR lKeyName="Description";

              if(rk.QueryValue(szValue,lKeyName,& pCount)== ERROR_SUCCESS)

              {

                     KeyValue=szValue;

                     SetDlgItemText(IDC_EDIT1,KeyValue);

              }

              else

              {

                     SetDlgItemText(IDC_EDIT1,"Query error");

              }

              //rk.SetValue(lKeyName,"HH");

       }

       else

       {

              SetDlgItemText(IDC_EDIT1,"Open error");

       }

    rk.Close();

3.加入一个键值:

LONG SetValue( DWORD dwValue, LPCTSTR lpszValueName );

LONG SetValue( LPCTSTR lpszValue, LPCTSTR lpszValueName = NULL );

LONG SetValue( HKEY hKeyParent, LPCTSTR lpszKeyName, LPCTSTR lpszValue, LPCTSTR lpszValueName = NULL );

有三个重载函数,大同小异。我们针对第二个举例,举一反三:

LONG lResult = 0;

    CRegKey reg;

    //open the required registry key

    LPCTSTR lpszKey = "Software\\Microsoft\\Internet Explorer\\Toolbar";

    lResult = reg.Open(HKEY_CURRENT_USER,lpszKey);

 
 
    //check if opened successfully

    if(ERROR_SUCCESS != lResult)

    {

        return FALSE;

    }         

    //set the value

    lResult = reg.SetValue(m_szFilePath,"BackBitmap");

    if(ERROR_SUCCESS != lResult)

    {

        return FALSE;

    }

    //done, close and return success

    reg.Close();

   
       m_szFilepath是一张图片的位置,通过这个函数,你的IE工具栏的背景就变成的你指定的图片了,很爽吧。

 
 
 
 
4.  删除一个键值:
LONG DeleteValue( LPCTSTR lpszValue );

lpszValue:你要删除的键值的名字.

例子:

LONG lResult = 0;

    CRegKey reg;

    //open the required registry key

    LPCTSTR lpszKey = "Software\\Microsoft\\Internet Explorer\\Toolbar";

    lResult = reg.Open(HKEY_CURRENT_USER,lpszKey);

 
 
    //check if opened successfully

    if(ERROR_SUCCESS != lResult)

    {

        return FALSE;

    }

    //delete the value "BackBitmap" from toolbar

    lResult = reg.DeleteValue("BackBitmap");

 
 
    //check if deleted successfully

    if(ERROR_SUCCESS != lResult)

    {

        return FALSE;   //perhaps value not found, if skin is not set

    }

    //done, return success

    reg.Close();

 
 
这样就去掉了你给IE工具栏设定的背景图片,也就是删掉了IE工具栏的BackBitmap键值。
 
 
一般来说最主要的操作就是这些了,是不是很简单啊。


posted @ 2005-10-31 22:01 纶巾客 阅读(995) 评论(0) 编辑
当我们用C#开发数据库访问程序的时候,通常有3种方式:odbc,oleDb,ado.net;其实我想对于这三种方式,这个问题都会出现,但是这次我遇到问题的时候用的是oleDb的方式,我们就用oleDb的方式来描述吧。

问题描述:

     我用OleDb的方式向Access数据里写数据,示例源码如下:

    string sql="select * from MultiTable";
    OleDbDataAdapter oleSub=new OleDbDataAdapter(sql,oleCn);
    OleDbCommandBuilder cb1=new OleDbCommandBuilder(oleSub);

   DataSet ds=new DataSet();

   oleSub.Fill(ds."MultiTable");

   DataTable dt=ds.Tables["MultiTable"];

   DataRow dr=dt.NewRow();

   dr["PRSERV"]="WS"+index.ToString().PadLeft(6,'0');

  dr["NUMBER"]="00063";

 ....................................

  dt.Rows.Add(dr);

  oleSub.Update(ds,"MulitTable");
  这段代码编译的时候是没有问题的,但是在运行的时候,会报出一个运行时错误:”Insert into 语句的语法错误“。

   用OleDbAdapter的时候,我并没有指定Insert语句,而是用OleDbCommandBuilder 来自动产生Insert 语句的。仔细想了一下,为什么会产生这个错误呢?我的结论是,可能这张表里的字段名使用了access系统的保留字。于是我在Access里创建了一个查询,自己写了一个insert sql,证实我的结论是正确的,NUMBER是系统的一个保留字,那怎么修改呢?

   一般来说,最简单的方法就是改掉这个字段名,换成非系统保留字的名字,但是库的结构是客户提供的,不允许修改,只有想别的办法。考虑以前的经验,操作Access,Sql Server的时候,如果表的字段中包含了系统的保留字的话,我们在字段外加上方括号就可以了,比如 insert into tblmultitable(prserv,[NUMBER]) values(.......)就可以了。可是从上面的代码中我们看到并没有什么地方我们可以指定Insert 语句。我想OleDbCommandBuilder应该是根据Adapter使用的select语句自动生成insert 语句的,所以只要给select 语句中的字段加上方括号就可以了,所以我作了如下的修改:

   string sql="select PRSERV,[NUMBER],PriorRef,Grantor,Grantee from MultiTable";

   修改完毕以后,测试以后,仍然产生以前的"Insert into 语句的语法错误";问题会出在哪里呢?我想应该还是在OleDbCommanBuilder上,一般来说,只需要这样用OleDbCommanBuilder类就可了:

    OleDbDataAdapter oleSub=new OleDbDataAdapter(sql,oleCn);
    OleDbCommandBuilder cb1=new OleDbCommandBuilder(oleSub);

    打开MSDN,看看OleDbCommanBuilder的类成员。发现两个很关键的属性:QuotePrefixQuoteSuffix;仔细想想,OleDb可以访问的数据类型非常多啊,所以关键字段的前缀,后缀的处理方法肯定不尽相同,比如访问Excel的时候表明应该写成[sheet1$的方式],所以提供这样一种方式是相当灵活的。接下来我再次修改代码,对这两个属性赋值:

    OleDbDataAdapter oleSub=new OleDbDataAdapter(sql,oleCn);
    OleDbCommandBuilder cb1=new OleDbCommandBuilder(oleSub);
    cb1.QuotePrefix="[";
    cb1.QuoteSuffix="]";

再次测试,通过!

  在网上搜索了一下,遇到这个问题的人不少,不过都是选择了改字段名,并不是一个彻底解决的方法,没有很好利用这个灵活性,所以把我遇到这个问题的解决方法写出来,希望对大家有所帮助。

posted @ 2005-10-31 21:53 纶巾客 阅读(2726) 评论(15) 编辑

公告

导航

统计