Ordinary, But Passional

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  30 随笔 :: 0 文章 :: 27 评论 :: 26 引用

2008年11月25日 #

  1. 准备一张图片,格式为BMP,长宽为64像素、128像素或256像素。
  2. 声明一个变量来存放纹理。
    GLuint texture[1];
  3. 用LoadBMP()载入图片,返回一个指向AUX_RGBImageRec的指针。
    AUX_RGBImageRec* texture_image[1];
    memset(texture_image, 0, sizeof(void*));
    texture_image[0] = LoadBMP(“winxp.bmp”);
  4. 创建一个纹理,并指定纹理的属性。
    glGenTextures(1, &texture[0]);
    glBindTextrue(GL_TEXTURE_2D, texture[0]);
  5. 生成纹理。
    glTexImage2D(GL_TEXTURE_2D, 0, 3, texture_image[0]->sizeX, texture_image[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, texture_image[0]->data;
  6. 设置当图片大于(小于)纹理大小时的显示方式。
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  7. 使纹理有效。
    glEnable(GL_TEXTURE_2D);
  8. 在画的过程中,如果有多个纹理,需要使用glBindTexture(GL_TEXTURE_2D, texture[0])选择纹理。
posted @ 2008-11-25 01:34 彭小虎(Tigerkin) 阅读(63) | 评论 (0)编辑

2008年11月17日 #

写了个俄罗斯方块,逻辑算法部分中规中矩,棋盘主要采用二维数组的数据结构,而每种方块样式都是Block类的一个对象,方便扩充;界面部分采用了DialogBox,用GDI画,同时还使用双缓冲技术防止画面闪烁。考虑到可以在RC文件里设计程序界面,所以采用了Dialogbox作为主界面,于是麻烦便来了:DialogBox无法接受WM_KEYDOWN中的VK_UP,VK_DOWN等,也就是说上下左右按键没法用。。试了几种办法,都不行,干脆换成了home,end,page up,page down键。玩的时候很不方便~等我再查查资料再改吧,先把这个有残缺的1.0版本发上来。

程序截图:tetris

下载地址:可执行文件源代码

posted @ 2008-11-17 00:57 彭小虎(Tigerkin) 阅读(68) | 评论 (0)编辑

2008年10月28日 #

很久没更新了。。发一个自己写的String类,可以自己指定使用ANSI还是UNICODE。这里下载

class String
{
private:
	wchar_t* wdata;
	char* data;
public:
	CharSet cs;
	String(CharSet _cs = USE_UNICODE, int size = 0);	// 默认使用UNICODE,不分配内存(size为0)
	String(const String& str, CharSet _cs = USE_ORIG);	// 必须是引用
	String(const char* str, CharSet _cs = USE_UNICODE);
	String(const wchar_t* str, CharSet _cs = USE_UNICODE);
	~String();

	// 可以从外部直接获得字符串在内存中的地址(小心使用~~)
	char* AnsiStr();		
	wchar_t* UnicodeStr();

	String& operator =(const String& str);
	String& operator =(const char* str);
	String& operator =(const wchar_t* str);

	String operator +(const String& str);
	String operator +(const char* str);
	String operator +(const wchar_t* str);

	String& operator +=(const String& str);
	String& operator +=(const char* str);
	String& operator +=(const wchar_t* str);
	
	int Find(const String& str);
	int Find(const char* str);
	int Find(const wchar_t* str);

	String SubStr(int start, int length);

	void Swap(String& str);

	int Length() const;
	void Clear();
};
posted @ 2008-10-28 20:37 彭小虎(Tigerkin) 阅读(61) | 评论 (0)编辑

2008年8月16日 #

我要在MSDN里搜Windows API DrawText函数,如图:

Google: 第一条就是。

Live Search:  找了半天没找到

posted @ 2008-08-16 12:22 彭小虎(Tigerkin) 阅读(103) | 评论 (1)编辑

以往写Windows程序,用的较多的是Delphi的VCL,MFC用的很少,总觉得不习惯,相比MFC我倒宁愿用清新简单的Windows API。呵呵。于是乎,我萌生了一个想法,自己来封装Windows API。开始动手。。

首先我找了一个比较简单的Window API程序,试着把他转换成面向对象的形式。程序尽管简单,但刚上来一个棘手的问题就出现了。。消息机制的封装。

我们都知道,Windows中比如点击按钮,移动窗口等等的交互操作都是由消息机制来完成的。每做一个动作,例如点击一个按钮,Windows便会产生一个相应的消息,在这里就是BN_CLICKED,假设点击按钮后会弹出一个窗口,里面显示若干文字,而这些点击按钮后产生的效果就需要由我们程序员来编写。体现在Windows API中便是“消息处理函数”,如下:

 

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     
switch (message)
     {
     
case BN_CLICKED:

          
//相关代码
          return 0 ;

     
case WM_DESTROY:
          PostQuitMessage (
0) ;
          
return 0 ;
     }
     
return DefWindowProc (hwnd, message, wParam, lParam) ;
}

 

每次都要写这么多case的确是挺麻烦的,于是我想用面向对象的方法解决他。

 

class MessageMap
{
public:
     
int count;  // 消息映射的数目
      Message* message[10];  // 可以存放10对消息映射
      template <typename T>
     
void Add(MessageType 消息名称, T* 对应的处理函数);  // 增加一对消息映射
};

template 
<typename T>
class Message
{
public:
     MessageType 消息名称;
     T
* 对应的处理函数;
     
void Run()
     {
          对应的处理函数();
     }
};

enum MessageType{}

 

这样做其实是有问题的,请看这一段:

 

class MessageMap
{
public:
     
      Message
* message[10];  // 由于Message是模板类,这里应该提供模板参数。这样就失去了模板的作用。
                                
// 我们使用模板就是为了能让他存储不同的函数指针。
      
};

 

想一想,如何用一个统一的接口来调用不同的函数?对了,那就是多态。

我们可以增加一个抽象的接口类来提供调用接口,而具体实现的类则由他派生。

 

class MessageInterface
{
public:
    MessageType type;
    
virtual ~MessageInterface() {}
    
virtual void Run() = 0;
}
;

template 
<typename T>
class Message : public MessageInterface
{
public:
    T
* classPtr;
    
void (T::* funcPtr)();
    Message(MessageType _type, T
* _classPtr, void (T::* _funcPtr)()) : classPtr(_classPtr), funcPtr(_funcPtr)
    
{
        type 
= _type;
    }

    
virtual void Run()
    
{
        
if (classPtr)
        
{
            (classPtr
->*funcPtr)();        // 注意调用函数指针时括号的用法
        }

    }
    
}
;

class MessageMap
{
public:
    
int count;
    MessageMap()
    
{
        count 
= 0;
        Add(DESTROY, 
this&MessageMap::OnDestroy); 
    }

    MessageInterface
* message[10];
    
void OnDestroy()
    
{
        PostQuitMessage(
0);
    }

    template 
<typename T>
    
void Add(MessageType type, T* classPtr, void (T::* funcPtr)())
    
{
        message[count
++= new Message<T>(type, classPtr, funcPtr);
    }

}
;

 

问题解决了!哈哈,测试成功!

具体的代码在这里,结构什么的还很不完善,仅仅是处理了消息机制而已,当作演示吧。

 

posted @ 2008-08-16 11:23 彭小虎(Tigerkin) 阅读(331) | 评论 (1)编辑

2008年8月7日 #

今天接到leader布置的一个任务,从TextBox继承一个新的控件并为其增加一些功能,其中一个功能如下:

Add a property: FormatString, when the text box lost focus, the content will be replace with string.Format(FormatString, actualContent),我在做第二个:“当textbox失去焦点时自动格式化文本”的地方遇到了问题。。。

简单起见,简化成“当textbox失去焦点时改变文本内容”。

一种方法是:

重写OnLeave()方法,如下:

protected override void OnLeave(EventArgs e)
{
        
base.OnLeave(e);
        
this.Text = "Override OnLeave";
}

另一种是给Leave事件增加一个订阅者:

private void NewReceiver(object sender, EventArgs e)
{
        
this.text = "NewReceiver";
        Invalidate();
}

//constructor
public MyTextBox()
{
        
this.Leave += new EventHandler(NewReceiver);
}

经测试,均可运行。

现在,把两段代码和在一起,并注释掉第一种方法:

protected override void OnLeave(EventArgs e)
{
    
base.OnLeave(e);
    
//this.Text = "Override OnLeave";
}

private void NewReceiver(object sender, EventArgs e)
{
    
this.text = "NewReceiver";
    Invalidate();
}

//constuctor
public MyTextBox()
{
    
this.Leave += new EventHandler(NewReceiver);
}

运行程序,测试,显示NewReceiver。

接下来再把base.OnLeave(e)注释掉:

protected override void OnLeave(EventArgs e)
{
    
//base.OnLeave(e);
    
//this.Text = "Override OnLeave";
}

private void NewReceiver(object sender, EventArgs e)
{
    
this.text = "NewReceiver";
    Invalidate();
}

//constuctor
public MyTextBox()
{
    
this.Leave += new EventHandler(NewReceiver);
}

运行,发现文本框失去焦点后不会改变内容,仍未空。由此,第二种方法失效了。为何?我们来看一下base.OnLeave()的内容:

protected virtual void OnLeave(EventArgs e)
{
    EventHandler handler 
= (EventHandler) base.Events[EventLeave];
    
if (handler != null)
    {
        handler(
this, e);
    }
}

原来,注释掉这段以后,handler(this, e)无法得到执行,也就没法激发事件,文本框内容当然也就没法改变了。

 

由此,我猜测,C#的事件触发过程大致是这样的:

文本框失去焦点 --> 触发Leave事件 --> 调用OnLeave()函数(这里是因为什么机制调用的?) --> 调用base.OnLeave() --> 再次触发Leave事件 --> 调用NewReceiver() --> 返回,执行this.text = "Override OnLeave"。

红色字,大家谁知道的,帮我解个惑吧~~

posted @ 2008-08-07 19:22 彭小虎(Tigerkin) 阅读(715) | 评论 (8)编辑

2008年8月2日 #

很多东西,不是你不会做,而是你不敢去做。久而久之,庸庸碌碌。。

要这么想:有什么东西是天生就会的呢!

posted @ 2008-08-02 17:35 彭小虎(Tigerkin) 阅读(62) | 评论 (1)编辑

2008年7月30日 #

一,公钥私钥
1,公钥和私钥成对出现
2,公开的密钥叫公钥,只有自己知道的叫私钥
3,用公钥加密的数据只有对应的私钥可以解密
4,用私钥加密的数据只有对应的公钥可以解密
5,如果可以用公钥解密,则必然是对应的私钥加的密
6,如果可以用私钥解密,则必然是对应的公钥加的密
明白了?

假设一下,我找了两个数字,一个是1,一个是2。我喜欢2这个数字,就保留起来,不告诉你们,然后我告诉大家,1是我的公钥。

我有一个文件,不能让别人看,我就用1加密了。别人找到了这个文件,但是他不知道2就是解密的私钥啊,所以他解不开,只有我可以用数字2,就是我的私钥,来解密。这样我就可以保护数据了。

我的好朋友x用我的公钥1加密了字符a,加密后成了b,放在网上。别人偷到了这个文件,但是别人解不开,因为别人不知道2就是我的私钥,只有我才能解密,解密后就得到a。这样,我们就可以传送加密的数据了。

现在我们知道用公钥加密,然后用私钥来解密,就可以解决安全传输的问题了。如果我用私钥加密一段数据(当然只有我可以用私钥加密,因为只有我知道2是我的私钥),结果所有的人都看到我的内容了,因为他们都知道我的公钥是1,那么这种加密有什么用处呢?

但是我的好朋友x说有人冒充我给他发信。怎么办呢?我把我要发的信,内容是c,用我的私钥2,加密,加密后的内容是d,发给x,再告诉他解密看是不是c。他用我的公钥1解密,发现果然是c。这个时候,他会想到,能够用我的公钥解密的数据,必然是用我的私钥加的密。只有我知道我得私钥,因此他就可以确认确实是我发的东西。这样我们就能确认发送方身份了。这个过程叫做数字签名。当然具体的过程要稍微复杂一些。用私钥来加密数据,用途就是数字签名。

好,我们复习一下:
1,公钥私钥成对出现
2,私钥只有我知道
3,大家可以用我的公钥给我发加密的信了
4,大家用我的公钥解密信的内容,看看能不能解开,能解开,说明是经过我的私钥加密了,就可以确认确实是我发的了。

总结一下结论:
1,用公钥加密数据,用私钥来解密数据
2,用私钥加密数据(数字签名),用公钥来验证数字签名。

在实际的使用中,公钥不会单独出现,总是以数字证书的方式出现,这样是为了公钥的安全性和有效性。

二,SSL
我和我得好朋友x,要进行安全的通信。这种通信可以是QQ聊天,很频繁的。用我的公钥加密数据就不行了,因为:
1,我的好朋友x没有公私钥对,我怎么给他发加密的消息啊? (注:实际情况中,可以双方都有公私钥对)
2,用公私钥加密运算很费时间,很慢,影响QQ效果。

好了,好朋友x,找了一个数字3,用我的公钥1,加密后发给我,说,我们以后就用这个数字来加密信息吧。我解开后,得到了数字3。这样,只有我们两个人知道这个秘密的数字3,别的人都不知道,因为他们既不知x挑了一个什么数字,加密后的内容他们也无法解开,我们把这个秘密的数字叫做会话密钥。

然后,我们选择一种对称密钥算法,比如DES,(对称算法是说,加密过程和解密过程是对称的,用一个密钥加密,可以用同一个密钥解密。使用公私钥的算法是非对称加密算法),来加密我们之间的通信内容。别人因为不知道3是我们的会话密钥,因而无法解密。

好,复习一下:
1,SSL实现安全的通信
2,通信双方使用一方或者双方的公钥来传递和约定会话密钥 (这个过程叫做握手)
3,双方使用会话密钥,来加密双方的通信内容

上面说的是原理。大家可能觉得比较复杂了,实际使用中,比这还要复杂。不过庆幸的是,好心的先行者们在操作系统或者相关的软件中实现了这层(Layer),并且起了一个难听的名字叫做SSL,(Secure Socket Layer)。

posted @ 2008-07-30 11:16 彭小虎(Tigerkin) 阅读(433) | 评论 (0)编辑

2008年3月16日 #

 

class String
{
public:
    String( 
const char *str = "" );
    
~String();
    String( 
const String &another )
    
{
        
const char *str = another.m_data;  // 可以正常访问
        /*省略*/
private:
    
char *m_data;
}
;

c++里,类的访问权限是class level,不是object level的。
访问权限只在编译时对编译器有效,在运行时,不存在访问权限这道栅栏。  

以下转自网上:

/**  
    *   请大家看看下面这段程序,它是能够正常编译连接运行的。但是为什么  
    *   assign成员函数没有错呢?谁能告诉我c++中关于这种情况的内幕?谢谢!  
    */  
   
  #include   <stdio.h>  
   
  class   Test    
  {  
  private:  
          int   a;  
  public:  
          Test(int);  
          void   assign(Test   const*   source);  
  };    
   
  void   Test::assign(Test   *source)  
  {  
          a   =   source->a;  
  }  
   
  int   main()  
  {  
          Test   t1(1),   t2(2);  
          t2.assign(&t1);  
  }  
   
  1:   关于ACCESS-CONTROL的定义  
   
      <<C++98   std/chapter   11>>:  
      1   A   member   of   a   class   can   be  
   
      --private;   that   is,   its   name   can   be   used     only     by      
          member     functions,   static     data     members,     and      
          friends     of     the     class     in   which   it   is   declared.  
   
      --protected;   that   is,   its   name   can   be   used   only   by  
          member     functions,   static     data     members,     and    
          friends     of     the     class     in   which   it   is   declared    
          and   by   member   functions,   static   data   members,      
          and     friends   of   classes   derived   from   this   class.  
   
      --public;     that     is,     its     name     can     be     used    
          anywhere   without   access   restriction.  
   
  2:   一些相关的note:  
        1)   name  
        ACCESS-CONTROL   只应用到name(simple   identifier).  
        按照上面的定义,ACCESS-CONTROL针对且只针对    
        member   of   class.        
        即使是涉及到模板,也只是关心name,    
        而不关心template-argument  
         
        2)   unnamed   object  
        无名对象不考虑access-control:  
        如下:  
        struct   A  
        {  
        private:  
              struct   B    
              {  
                  int   i;  
              };  
              B   m_b;  
        public:  
              B&   f()   {   return   m_b;   }            
        };  
        int   main()  
        {  
            A   a;  
            f()->i;   //   only   names   are   f,   i,    
                            //   f   and   i   is   public,    
                            //   so   it's   legal   even    
                            //   if   B   in   private   A   member  
        }        
        3)   关于protected   member   name有一个例外情况,  
              参见(4:)中例子的new   note  
   
  3:   让人迷惑的代码段的注记  
   
        void   Test::assign(Test   *source)  
        {  
          a   =   source->a;  
          /**  
            1)   这里出现的name是  
                  void,   Test,   assign,   source,   a  
            2)   void,   Test,   source,    
                不是class   member,    
                不做access-control考虑  
            3)   assign是成员函数名,    
                  但我们只是定义它,  
                  不在这里使用,  
                  也不做access-control考虑  
   
            4)a是private   Test   member,    
                  可以在A的成员函数中使用,  
                  现在刚好是在Test的  
                  assign成员函数体内。  
                   
            5)   but   what   about   "source->a":  
                  OK,   a   in   "source->a"   means    
                  a   is   a   member   name   of   source's   class   Test  
                  and   used   in   Test   member   function,    
                  everything   is   fine!!!  
                  (still   confusing,   see   following   example   ...)  
            */  
        }  
   
  4:   更加清楚的例子(我的)注记  
       
        struct   Base  
        {  
        protected:  
            int   m_protected;  
        };  
   
        struct   Son2   :   Base   {};  
   
        struct   Son1   :   Base  
        {  
   
            void   foo(Son1&   s)  
            {  
                s.m_protected;           /**  
                                                  new   note:  
                                                  same   as   3/5)  
                                                  */  
            }  
   
            void   foo(Base&   b)  
            {  
                b.m_protected;    /**  
                                          new   note:  
                                          m_protected   in   "b.m_protected"   means:  
                                              m_protected   is   Base(b's   type)   class    
                                              member,   not   Son1   class   member  
                                          which   means:  
                                              Base's   protected   member   is   used  
                                              in   Son1's   member   function    
                                          By   definition,   it's   legal,   but  
                                          因为C++标准规定一个关于  
                                          proected   member的例外情况,  
                                              When   a   member   function   of   a      
                                              derived     class   references      
                                              a     protected   nonstatic   member  
                                              of   a   base   class,   an   access   check    
                                              applies   in   addition     to     those    
                                              described   earlier   in   this   clause:  
                                                Except   when   forming   a   pointer   to  
                                                member,the   access   must   be   through    
                                                          a   pointer   to,  
                                                          reference   to,      
                                                          <---我们的情况  
                                                          or   object              
                                                          <---下一个成员函数的情况  
                                                      of   the   derived   class   itself    
                                              (or   any   class   derived   from   that   class).  
                                          因为儿子不能管老子,所以结论是  
                                          illegal    
                                          */  
   
            }  
            void   foo(Base   b)  
            {  
                b.m_protected;  /**  
                                        new   note:  
                                        illegal   :   儿子不能管老子  
                                        原因同   void   foo(Base&   c)的分析。  
                                        */  
            }    
      };  

posted @ 2008-03-16 19:29 彭小虎(Tigerkin) 阅读(87) | 评论 (1)编辑

2008年3月8日 #

很有用的,所以把它记下来

1 CString,int,string,char*之间的转换  
string 转 CString  
CString.format("%s", string.c_str());  

char 转 CString  
CString.format("%s", char*);  

char 转 string  
string s(char *);  

string 转 char *  
char *p = string.c_str();  

 //  CString转std::string
 CString str = dlg.GetPathName();
 setlocale(LC_ALL, "chs");
 char *p = new char[256];
 wcstombs( p, str, 256 );
 m_fileName = p;

1,string -> CString  
CString.format("%s", string.c_str());  
用c_str()确实比data()要好.  
2,char -> string  
string s(char *);  
你的只能初始化,在不是初始化的地方最好还是用assign().  
3,CString -> string  
string s(CString.GetBuffer());  
GetBuffer()后一定要ReleaseBuffer(),否则就没有释放缓冲区所占的空间.  


《C++标准函数库》中说的  
有三个函数可以将字符串的内容转换为字符数组和C—string  
1.data(),返回没有”\0“的字符串数组  
2,c_str(),返回有”\0“的字符串数组  
3,copy()  


CString互转int  

将字符转换为整数,可以使用atoi、_atoi64或atol。  
而将数字转换为CString变量,可以使用CString的Format函数。如  
CString s;  
int i = 64;  
s.Format("%d", i)  
Format函数的功能很强,值得你研究一下。  

void CStrDlg::OnButton1()  
{  
// TODO: Add your control notification handler code here  
CString  
ss="1212.12";  
int temp=atoi(ss);  
CString aa;  
aa.Format("%d",temp);  
AfxMessageBox("var is " + aa);  
}  

sart.Format("%s",buf);  

CString互转char*  

///char * TO cstring  
CString strtest;  
char * charpoint;  
charpoint="give string a value";  
strtest=charpoint;  


///cstring TO char *  
charpoint=strtest.GetBuffer(strtest.GetLength());  

标准C里没有string,char *==char []==string  

可以用CString.Format("%s",char *)这个方法来将char *转成CString。要把CString转成char *,用操作符(LPCSTR)CString就可以了。  


CString转换 char[100]  

char a[100];  
CString str("aaaaaa");  
strncpy(a,(LPCTSTR)str,sizeof(a));  
2 CString类型的转换成int  
CString类型的转换成int  
将字符转换为整数,可以使用atoi、_atoi64或atol。  

//CString aaa = "16" ;
//int int_chage = atoi((lpcstr)aaa) ;  


而将数字转换为CString变量,可以使用CString的Format函数。如  
CString s;  
int i = 64;  
s.Format("%d", i)  
Format函数的功能很强,值得你研究一下。  
如果是使用char数组,也可以使用sprintf函数。

//CString ss="1212.12";  
//int temp=atoi(ss);  
//CString aa;  
//aa.Format("%d",temp);  


数字->字符串除了用CString::Format,还有FormatV、sprintf和不需要借助于Afx的itoa  

3 char* 在装int  
#include <stdlib.h>
  
int atoi(const char *nptr);
long atol(const char *nptr);
long long atoll(const char *nptr);
long long atoq(const char *nptr);  

4 CString,int,string,char*之间的转换  
string aa("aaa");
char *c=aa.c_str();


cannot convert from 'const char *' to 'char *'
const char *c=aa.c_str();  

5 CString,int,string,char*之间的转换  
string.c_str()只能转换成const char *,
要转成char *这样写:

string mngName;
char t[200]; memset(t,0,200); strcpy(t,mngName.c_str());  

posted @ 2008-03-08 23:50 彭小虎(Tigerkin) 阅读(4283) | 评论 (4)编辑