我的记事本

       在这个CSDN的博客,也曾想多写些技术文章,把自己的开发感悟和经验记录下来,供那些同在这条路上奔波劳累码农们多少减轻点负担。但是,一番忙碌后,项目结束了,人也累了,就没有了写的激情。这个博客对于那些辛勤写作的程序猿们,也没有什么奖励,偶尔想下载的小工具、小程序,也得充值成为VIP才行,于是就更没有了动手的激情~~~~~。

       开这个博客,就当个记事薄,平时偶尔解决个小问题,随手记录,日后再遇到,也有个参考,如果恰巧有帮到某个“猿”,就算是赚了~~~~~~~~~~~~。

     (1)要用tomcat发布个小网页,在自己机器上挺好的,那些运行所需要环境,也不知什么时候就具备了,要布置到别人的服务器上,事先准备好,总是好的,可以避免现场的混乱,浪费时间。最好把需要的环境都放到tomcat的同一个目录,最紧要的是Java的JDK或JRE,这是tomcat必须的运行环境,注意tomcat对Java版本也是要求的。

       tomcat是会自己检查主机的Java环境并使用的,也会自己检查本尊的安装目录,如果主机环境变量没有Java的环境或者其版本不满足你的tomcat的要求,总会有点不方便。为避免现场的忙乱,最好是直接把需要的版本拷贝到tomcat目录下并设置,就可以在客户那里复制粘贴及了事,可不潇洒........。

       啰嗦半天了,言归正传:将需要的Java JDK或JRE目录拷贝到tomcat目录下,在tomcat\bin子目录下,找到批处理文件:startup.bat 。

在call "%EXECUTABLE%" start %CMD_LINE_ARGS%之前,加上一句:

           set "JAVA_HOME=%CATALINA_HOME%\jdk1.8.0_25"    //这里应设置为你的版本

 或者:set "JRE_HOME=%CATALINA_HOME%\jre1.8.0_25"

 注意:tomcat一般使用JRE,如果它检测到JRE存在,会直接使用你设定目录下的JRE目录。

          CATALINA_HOME是tomcat的安装目录,它会自己检测到,不要任何设置,倒很方便。

          在同一目录下,还有一个setclasspath.bat ,这里会设置JAVA的位置,如果在startup.bat

         做了设置,那么它就会跳过JAVA目录的设置,相当于截了胡。其实在这个目录中设置也是

         可以的。

(2)在各种JAVA开发应用中,经常要适应logger,对各种的操作或处理信息做日志文件。通常使用apache的log4j,如果没有正确的配置,经常会出现如下的错误提示:

log4j:WARN No appenders could be found for logger (SmartLic.SmartLicClient).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

在不同的开发环境下可能解决方法不同,但总体来讲,要确定

(1)需要一个log4j的设置正确配置文件log4j.properties.

  (2)文件的位置,应在正确目录下。

下面是一个正确的配置文件范本,可以将日志信息输出到文件中:

log4j.rootLogger=INFO,logfile
log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.ImmediateFlush=true
log4j.appender.logfile.Append=true
log4j.appender.logfile.Threshold=DEBUG 
log4j.appender.logfile.File=log\\logs.log     //这个目录根据实际情况修改。
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

第二个问题,可以通过一个函数指定:

PropertyConfigurator.configure("log4j.properties");

(3)今天又遇到一个常见的问题:UDF-8编码的中文在GBK的JAVA开发环境中出现乱码,需要从UTF-8编码的字符串,转换为UNICODE的字符串,本以为这个是常见的问题,所有就在网上百度解决方法,结果很是意外,虽然有很多博客文章谈及这个问题,但是花了几个小时,也没有找到能用程序,很多朋友的程序和解决方法,拿来却不可用,只有自己动手了。理解了下UTF-8编码的知识:一个中文字符是3个字节编码,首字符的高四位,从高位到低位有多少个比特为1,则表示有几个字节的编码,首字节的低四位对应该汉字编码的UNICODE编码的高四位,第二字节的高2位为10,低6位为对应汉字UNICODE编码的中间6位,第三字节的高2位也是10,低6位对UNICODE编码的低6位,这样就可以得到该汉字16位的UNICODE编码。之后就可以转换为UNICODE的字符串了。程序如下,供参考。调用前,确保byteArr是UTF-8编码的字节数组。通过JAVA函数getBytes可以很容易得到UTF-8编码的字节数组。

          public static String UDF8TouUDF16BE(byte[] byteArr) 
   {   
      StringBuffer sb=new StringBuffer();
      String ch="";
       byte[] bs=new byte[]{0,0};
       int len=byteArr.length;
       int b1=0,b2=0,b3=0,b=0;
       if (len%3!=0) return "";   
       for (int i=0;i<len;i=i+3)
       {
          b1=byteArr[i]&(byte)0x0f;
          b1=b1<<12;
          b2=byteArr[i+1]&(byte)0x3f;
          b2=b2<<6;
          b3=byteArr[i+2]&(byte)0x3f;
          b=b1+b2+b3;
          bs[0]=(byte)(b>>>8);
          bs[1]=(byte)(b&0x00ff);
          try {
            ch=new String(bs,"UTF-16BE");
            sb.append(ch);
          } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
         }   
       }
     return sb.toString();
   }

(3)CString 和  char*  的转换

    将char*转换为CString 比较简单  直接使用char*使用CString的构造函数生成CString

     char str[10]="abc";CString cstr(str);

   CString 转为 char* :

    CString是MFC封装的字符串类型,如果项目字符集属性设置为UNICODE:使用wcstombs_s可以转换为char*,如果项目字符属性为多字节或为未设置:使用getBuffer(0), 即可获取到char*的字符串。

(4)BMP格式图像文件的结构(2022.01.25)

    BMP格式的图像文件一般由四个部分组成:

   1.文件信息头。所有该类型文件必须有的数据结构,14字节,其结构定义为:

     typedef struct tagBITMAPFILEHEADER {
        WORD    bfType;      //文件类型标志,必须是0x4D42(19778)
        DWORD   bfSize;     //文件大小
        WORD    bfReserved1;    //保留,为0
        WORD    bfReserved2;    //保留,为0
        DWORD   bfOffBits;         //颜色数据或颜色索引数据到文件首部的偏移。
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
2.图像数据信息结构,40字节,其定义为:

   typedef struct tagBITMAPINFOHEADER{
        DWORD      biSize;                //本结构大小
        LONG       biWidth;                 //图像的宽度,单位是像素
        LONG       biHeight;               //图像的高度,  像素
        WORD       biPlanes;             //图像位面,一般都是1
        WORD       biBitCount;          //每像素比特数
        DWORD      biCompression; //压缩方式:RLE4或RLE8,一般不压缩,为0
        DWORD      biSizeImage;     //颜色数据或颜色索引数据的大小。多种方式可以计算,可以为0
        LONG       biXPelsPerMeter; //每米X方向像素数
        LONG       biYPelsPerMeter;  //每米Y方向像素数
        DWORD      biClrUsed;          //使用的颜色数。可以为0,指所有颜色
        DWORD      biClrImportant;   //重要的颜色数。 为0,指所有颜色都重要
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

3.调色板。24位的真彩图像,没有调色板。

    颜色深度为1:2个色板,深度4:16个色板,深度8:256个色板

每种颜色板的结构:

typedef struct tagRGBQUAD {
        BYTE    rgbBlue;
        BYTE    rgbGreen;
        BYTE    rgbRed;
        BYTE    rgbReserved;
} RGBQUAD;

4.这一部分对24位真彩图像,为RGB的颜色值,其结构为:

typedef struct tagRGBTRIPLE {
        BYTE    rgbtBlue;
        BYTE    rgbtGreen;
        BYTE    rgbtRed;
} RGBTRIPLE, *PRGBTRIPLE, NEAR *NPRGBTRIPLE, FAR *LPRGBTRIPLE;

其它深度的图像,这部分是图像调色板的索引值。

需要注意的是:图像的每行数据的字节数必须是4的整数倍,不足的需要补0。PHOTOSHOP生成的BMP文件格式结尾可能会加两个值为0字节。(待证实)

编程注意事项:

1. 应灵活应用上述结构定义,对从文件中读取的数据进行强制类型转换,可以方便获取有关数据。

2.在使用StretchDIBits时,有个结构:BITMAPINFO

int   WINAPI StretchDIBits(_In_ HDC hdc, _In_ int xDest, _In_ int yDest, _In_ int DestWidth, _In_ int DestHeight, _In_ int xSrc, _In_ int ySrc, _In_ int SrcWidth, _In_ int SrcHeight,
        _In_opt_ CONST VOID * lpBits, _In_ CONST BITMAPINFO * lpbmi, _In_ UINT iUsage, _In_ DWORD rop);

typedef struct tagBITMAPINFO {
    BITMAPINFOHEADER    bmiHeader;
    RGBQUAD             bmiColors[1];
} BITMAPINFO, FAR *LPBITMAPINFO, *PBITMAPINFO;

指向这个结构的指针要注意:这个结构中的第二个成员,其实是一个调色板。要正确的显示,这个指针指向的数据必须包含有需显示图像的图像信息和调色板【必须指向BITMAPINFOHEADER的指针】。不需要提供其它的调色板,这个成员本身包含调色板的指针。VOID * lpBits参数是图像数据的指针。

3.在图像处理时,应该注意每行额外补充的数据0。

4.VC  MFC实现BMP文件的处理,可以创建SDI应用程序。SDI应用程序,包含三个重要的类:主窗口:CMainFrm,文档类DOC和视类View。可以定义一个CDib类,专用于处理BMP图像,打开图像时,获取所有的图像数据和相关结构的指针。在DOC类中,可以在打开文件时,完成CDib对象的初始化,在View类中的OnDraw事件中,完成显示。在CMainFrm中添加菜单和对话框的方法是:在CMainFrm中的OnCreate方法中:

CMenu *pFrameMenu = GetMenu();
    if (pFrameMenu!=NULL)
    {
        CMenu* pNewPopMenu = new CMenu;
        pNewPopMenu->CreatePopupMenu();
        pNewPopMenu->AppendMenuW(MF_STRING, ID_MENU_NORMAL,_T("常规"));
        pNewPopMenu->AppendMenu(MF_STRING, ID_MENU_TODOWN, _T("向下扫"));
        pNewPopMenu->AppendMenuW(MF_STRING, ID_MENU_TOUP,_T("向上扫"));
        pNewPopMenu->AppendMenu(MF_STRING, ID_MENU_TORIGHT, _T("向右扫"));
        pNewPopMenu->AppendMenuW(MF_STRING, ID_MENU_TOLEFT,_T("向左扫"));
        pNewPopMenu->AppendMenuW(MF_STRING, ID_MENU_GRADUAL,_T("淡入"));
        pFrameMenu->InsertMenuW(3, MF_BYPOSITION | MF_POPUP, (UINT)pNewPopMenu->m_hMenu,_T("显示(D)"));

        CMenu* pNewPopMenu2 = new CMenu;
        pNewPopMenu2->CreatePopupMenu();
        pNewPopMenu2->AppendMenuW(MF_STRING, ID_MENU_MOVE,_T("平移"));
        pNewPopMenu2->AppendMenuW(MF_STRING, ID_MENU_STRETCH,_T("放大"));
        pNewPopMenu2->AppendMenuW(MF_STRING, ID_MENU_XMIRROR,_T("横向镜像"));
        pNewPopMenu2->AppendMenuW(MF_STRING, ID_MENU_YMIRROR,_T("纵向镜像"));
        pFrameMenu->InsertMenuW(4, MF_BYPOSITION | MF_POPUP, (UINT)pNewPopMenu2->m_hMenu,_T("变换(T)"));
    }

  上述代码,可以在主菜单中添加菜单项并附加上弹出式菜单。其中的菜单ID需要在Resource.h中定义。

 然后,需要给菜单添加事件处理代码:包括消息映射和事件处理代码。

如果事件处理中,需要弹出对话框完成参数的输入,按如下方式操作:

 (a) 在解决方案右击鼠标,选择【添加】【资源】-【对话框】。之后完成对话框中控件的设计。

 (b)在解决方案右击鼠标,  选择【添加】【类】【MFC】,这时注意选择基类为CDiaglog(EX), 选 

    择刚设计对话框资源。然后,就可以给对话框添加事件处理、变量等。

(5)VS  MFC SDI方式下,有时需要非模式对话框,与上面提到的模式对话框的产生有些不同。总结如下:首先还是在资源中添加一个对话框资源,然后以CDialog或CDialogEx为基类添加一个MFC类,选择刚创建的对话框资源ID,就产生了一个对话框类。和模式对话框不同的是,不能用Domodal方法显示对话框:例如,

    if (m_pThresholdDlg==NULL)
    {
        m_pThresholdDlg=new CThresholdDlg(pDib,this);
        m_pThresholdDlg->Create(IDD_DIALOG4,this);
    }
    m_pThresholdDlg->ShowWindow(SW_SHOW);

    这里m_pThresholdDlg是在对话框的父窗口中定义的一个所设计对话框的指针变量。

   上面的代码就会显示一个非模式对话框。注意,退出对话框的时候,应该向父窗口发送信息,以便释放对话框资源。主窗口退出,也应该向对话框发送退出消息,释放相关资源。

(6)获取本机IP地址

           获取本机IP地址或主机名是常用的操作,下面是关键代码:

          必须先启动网络驱动。WSASetUP.

 if((hostinfo = gethostbyname(hn))!= NULL) //获得本地ipv4地址
     {  //hn是主机名字符串,

          for (int i=0;;i++)   //循环获取所有IP

         {
            p = hostinfo->h_addr_list[i];
            if (p!=NULL)
               szIP = ::inet_ntoa(*(in_addr*)p);  //这个串中就是IP
            else break;
       }  

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值