蛰伏半月有余,一直在准备期末考试,期间抽空研究了一些Android的源代码,现在我就把在这其中的一些收获分享给大家。

今天想分享给大家的是二维码扫描。说起二维码,大家一定不会陌生,尤其是微信火了以后,在我们的生活中几乎随处都可以看到二维码的影

子。相关科技媒体甚至把二维码当成是未来移动互联网的入口,因此研究二维码的相关技术就显得意义非凡。目前在移动开发领域,使用最为广泛的二

维码库有两个,分别是ZXing和ZBar,其中ZXing在Android开发中较为常见,而ZBar则在IOS开发中较为常见,更重要的一点是,这两个库都是开源

的,因此我们可以从源代码中获得很多有用的东西。关于ZXing,网上有很多相关的博文,我今天不想多说,我今天想说的是ZBar,你可能会说,ZBar

不是用在IOS中,怎么今天要说ZBar呢?其实我是从这两个库使用的难易程度来选择的,ZXing功能强大,但是使用起来比较繁琐,网上有很多简化的

教程,大家可以自行前去研究。相比较而言,ZBar则比较简单,使用起来容易上手,因此我们今天选择了ZBar作为我们的库来使用。

一、准备工作

下载ZBar的SDK:由于ZBar的项目托管在sourceforge,所以在这里给出下载地址:http://download.csdn.net/detail/qinyuanpei/6794713

二、导入项目

下载完成后,我们直接解压,可以看到下面的目录结构

打开android文件夹,我们可以找到一个Example的文件夹,这是官方给出的示例代码,我们下面的所有工作都是基于这个示例程序而来。我们

自行创建一个Android项目,并将这两个文件拷贝到我们的项目中,同时引入ZBar相关的库文件。

三、建立布局

首先建立主界面,即扫描二维码的界面,界面布局代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="40dp"android:background="@drawable/title_bg" ><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:layout_centerVertical="true"android:text="@string/Scan"android:textColor="#ffffff"android:textSize="18sp" /><Buttonandroid:id="@+id/BtnAbout"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentRight="true"android:layout_alignParentTop="true"android:text="@string/BtnAbout" /></RelativeLayout><FrameLayoutandroid:id="@+id/cameraPreview"android:layout_width="match_parent"android:layout_height="0dip"android:layout_weight="1"/>
</LinearLayout>

实现的布局效果如下图所示:

接下里,我们在来设计一个用于显示结果的界面,界面布局代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#ffffff"android:orientation="vertical" ><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="40dp"android:background="@drawable/title_bg" ><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerHorizontal="true"android:layout_centerVertical="true"android:textSize="18sp"android:textColor="#ffffff"android:text="@string/Result" /><Buttonandroid:id="@+id/BtnBack"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_alignParentTop="true"android:text="@string/BtnBack" /></RelativeLayout><TextViewandroid:id="@+id/TextResult"android:layout_width="match_parent"android:layout_height="wrap_content"android:textColor="#000000"android:layout_margin="8dp"android:textIsSelectable="true"/>
</LinearLayout>

实现的界面效果如图所示:

四、编写代码

首先我们来写一个用于扫描的相机预览视图CameraPreview,此文件由ZBar的SDK提供,这里我做了下简单的修改

package com.Android.ZBar4Android;import java.io.IOException;
import android.util.Log;import android.view.SurfaceView;
import android.view.SurfaceHolder;import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.AutoFocusCallback;//此类由ZBar项目的SDK提供,我做了下修改
@SuppressLint("ViewConstructor")
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback
{private SurfaceHolder mHolder;private Camera mCamera;private PreviewCallback mPreviewCallBack;private AutoFocusCallback mAutoFocusCallBack;public CameraPreview(Context context, Camera camera,PreviewCallback previewCb,AutoFocusCallback autoFocusCb) {super(context);mCamera = camera;mPreviewCallBack = previewCb;mAutoFocusCallBack = autoFocusCb;/* * 自动聚焦* 要求API版本>9*/Camera.Parameters parameters = camera.getParameters();for (String f : parameters.getSupportedFocusModes()) {if (f == Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) {parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);mAutoFocusCallBack = null;break;}}// Install a SurfaceHolder.Callback so we get notified when the// underlying surface is created and destroyed.mHolder = getHolder();mHolder.addCallback(this);// deprecated setting, but required on Android versions prior to 3.0mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);}public void surfaceCreated(SurfaceHolder holder) {// The Surface has been created, now tell the camera where to draw the preview.try {mCamera.setPreviewDisplay(holder);} catch (IOException e) {Log.d("DBG", "Error setting camera preview: " + e.getMessage());}}public void surfaceDestroyed(SurfaceHolder holder) {// Camera preview released in activity}public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {/** If your preview can change or rotate, take care of those events here.* Make sure to stop the preview before resizing or reformatting it.*/if (mHolder.getSurface() == null){// preview surface does not existreturn;}// stop preview before making changestry {mCamera.stopPreview();} catch (Exception e){// ignore: tried to stop a non-existent preview}try {// Hard code camera surface rotation 90 degs to match Activity view in portraitmCamera.setDisplayOrientation(90);mCamera.setPreviewDisplay(mHolder);mCamera.setPreviewCallback(mPreviewCallBack);mCamera.startPreview();mCamera.autoFocus(mAutoFocusCallBack);} catch (Exception e){Log.d("DBG", "Error starting camera preview: " + e.getMessage());}}/** 绘制校准框* 修改:秦元培* 时间:2013年11月22日* */@Overrideprotected void onDraw(Canvas mCanvas) {//这里不会写了?}
}

接下来,我们来编写主界面的逻辑代码,在这里我们需要搞清楚的几个问题有:

1、相机的获取及相机的交互处理

2、二维码图片的获取

3、二维码图片的解析

对于第一个问题,需要我们深入地了解相机的工作原理,即我们需要了解Camera类。

获取相机的代码如下:

//获取照相机的方法public static Camera getCameraInstance(){Camera mCamera = null;try{mCamera = Camera.open();//没有后置摄像头,尝试打开前置摄像头*******************if (mCamera == null){Camera.CameraInfo mCameraInfo = new Camera.CameraInfo();int cameraCount = Camera.getNumberOfCameras(); for (int camIdx = 0; camIdx < cameraCount; camIdx++){Camera.getCameraInfo(camIdx, mCameraInfo); if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){mCamera = Camera.open(camIdx);                        }}}}catch (Exception e){e.printStackTrace();}return mCamera;}

释放照相机的方法

//释放照相机private void releaseCamera(){if (mCamera != null){IsPreview = false;mCamera.setPreviewCallback(null);mCamera.release();mCamera = null;}}

相机反馈的方法,即扫描到二维码后的处理

PreviewCallback previewCb = new PreviewCallback(){public void onPreviewFrame(byte[] data, Camera camera){Camera.Parameters parameters = camera.getParameters();//获取扫描图片的大小Size mSize = parameters.getPreviewSize();//构造存储图片的ImageImage mResult = new Image(mSize.width, mSize.height, "Y800");//第三个参数不知道是干嘛的//设置Image的数据资源mResult.setData(data);//获取扫描结果的代码int mResultCode = mScanner.scanImage(mResult);//如果代码不为0,表示扫描成功if (mResultCode != 0){//停止扫描IsPreview = false;mCamera.setPreviewCallback(null);mCamera.stopPreview();//开始解析扫描图片SymbolSet Syms = mScanner.getResults();for (Symbol mSym : Syms){//mSym.getType()方法可以获取扫描的类型,ZBar支持多种扫描类型,这里实现了条形码、二维码、ISBN码的识别if (mSym.getType() == Symbol.CODE128 || mSym.getType() == Symbol.QRCODE || mSym.getType() == Symbol.CODABAR ||   mSym.getType() == Symbol.ISBN10 ||mSym.getType() == Symbol.ISBN13|| mSym.getType()==Symbol.DATABAR ||mSym.getType()==Symbol.DATABAR_EXP || mSym.getType()==Symbol.I25){//添加震动效果,提示用户扫描完成Vibrator mVibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE);mVibrator.vibrate(400);Intent intent=new Intent(MainActivity.this,ResultActivity.class);intent.putExtra("ScanResult", "扫描类型:"+GetResultByCode(mSym.getType())+"\n"+ mSym.getData());//这里需要注意的是,getData方法才是最终返回识别结果的方法//但是这个方法是返回一个标识型的字符串,换言之,返回的值中包含每个字符串的含义//例如N代表姓名,URL代表一个Web地址等等,其它的暂时不清楚,如果可以对这个进行一个较好的分割//效果会更好,如果需要返回扫描的图片,可以对Image做一个合适的处理startActivity(intent);IsScanned = true;}else{//否则继续扫描IsScanned = false;mCamera.setPreviewCallback(previewCb);mCamera.startPreview();IsPreview = true;mCamera.autoFocus(autoFocusCB);}}}}};

对于第二个问题,从上面的代码中我们可以看出,Image类用于获取二维码图片,ImageScanner类用于对图片的初步解析,而图片的最终解析是在SymbolSet类和

Symbol中去实现的,由此,第三个问题得以解答。下面给出完整代码:

/** ZBar4Android* 作者:秦元培* 时间:2013年12月21日* 需要解决的问题有:* 1、返回内容的正则解析* 2、如果锁屏后打开程序会报错* 3、没有校正框,画不出来啊,郁闷* 4、可能会与其它相机应用冲突,如微信* 5、条形码还是读不出来*/
package com.Android.ZBar4Android;import com.Android.ZBar4Android.CameraPreview;
import com.Android.ZBar4Android.R;import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.FrameLayout;
import android.widget.Button;
import android.widget.PopupWindow;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.Size;import net.sourceforge.zbar.ImageScanner;
import net.sourceforge.zbar.Image;
import net.sourceforge.zbar.Symbol;
import net.sourceforge.zbar.SymbolSet;
import net.sourceforge.zbar.Config;public class MainActivity extends Activity
{//关于按钮private Button BtnAbout;//相机private Camera mCamera;//预览视图private CameraPreview mPreview;//自动聚焦private Handler mAutoFocusHandler;//图片扫描器private ImageScanner mScanner;//弹出窗口private PopupWindow mPopupWindow;//是否扫描完毕private boolean IsScanned = false;//是否处于预览状态private boolean IsPreview = true;//是否显示弹出层private boolean IsShowPopup=false;//加载iconvlibstatic{System.loadLibrary("iconv");}public void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);//去除标题栏requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.layout_main);//设置屏幕方向为竖屏setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);//自动聚焦线程mAutoFocusHandler = new Handler();//获取相机实例mCamera = getCameraInstance();if(mCamera == null){//在这里写下获取相机失败的代码AlertDialog.Builder mBuilder=new AlertDialog.Builder(this);mBuilder.setTitle("ZBar4Android");mBuilder.setMessage("ZBar4Android获取相机失败,请重试!");mBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener(){@Overridepublic void onClick(DialogInterface mDialogInterface, int mIndex) {MainActivity.this.finish();}});AlertDialog mDialog=mBuilder.create();mDialog.show();}//实例化ScannermScanner = new ImageScanner();mScanner.setConfig(0, Config.X_DENSITY, 3);mScanner.setConfig(0, Config.Y_DENSITY, 3);//设置相机预览视图mPreview = new CameraPreview(this, mCamera, previewCb, autoFocusCB);FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview);preview.addView(mPreview);if (IsScanned){IsScanned = false;mCamera.setPreviewCallback(previewCb);mCamera.startPreview();IsPreview = true;mCamera.autoFocus(autoFocusCB);}//获取BtnAbout,显示程序信息BtnAbout=(Button)findViewById(R.id.BtnAbout);BtnAbout.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v){//如果弹出层已打开,销毁弹出层if(IsShowPopup){mPopupWindow.dismiss();IsShowPopup=false;}else{//否则显示弹出层mPopupWindow=new PopupWindow();LayoutInflater mInflater=LayoutInflater.from(getApplicationContext());View view=mInflater.inflate(R.layout.layout_about, null);mPopupWindow.setContentView(view);mPopupWindow.setWidth(LayoutParams.WRAP_CONTENT);mPopupWindow.setHeight(LayoutParams.WRAP_CONTENT);mPopupWindow.showAtLocation(mPreview, 0, 100, 100);IsShowPopup=true;}} });}//实现Pause方法public void onPause(){super.onPause();releaseCamera();}//获取照相机的方法public static Camera getCameraInstance(){Camera mCamera = null;try{mCamera = Camera.open();//没有后置摄像头,尝试打开前置摄像头*******************if (mCamera == null){Camera.CameraInfo mCameraInfo = new Camera.CameraInfo();int cameraCount = Camera.getNumberOfCameras(); for (int camIdx = 0; camIdx < cameraCount; camIdx++){Camera.getCameraInfo(camIdx, mCameraInfo); if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){mCamera = Camera.open(camIdx);                        }}}}catch (Exception e){e.printStackTrace();}return mCamera;}//释放照相机private void releaseCamera(){if (mCamera != null){IsPreview = false;mCamera.setPreviewCallback(null);mCamera.release();mCamera = null;}}private Runnable doAutoFocus = new Runnable(){public void run(){if (IsPreview)mCamera.autoFocus(autoFocusCB);}};PreviewCallback previewCb = new PreviewCallback(){public void onPreviewFrame(byte[] data, Camera camera){Camera.Parameters parameters = camera.getParameters();//获取扫描图片的大小Size mSize = parameters.getPreviewSize();//构造存储图片的ImageImage mResult = new Image(mSize.width, mSize.height, "Y800");//第三个参数不知道是干嘛的//设置Image的数据资源mResult.setData(data);//获取扫描结果的代码int mResultCode = mScanner.scanImage(mResult);//如果代码不为0,表示扫描成功if (mResultCode != 0){//停止扫描IsPreview = false;mCamera.setPreviewCallback(null);mCamera.stopPreview();//开始解析扫描图片SymbolSet Syms = mScanner.getResults();for (Symbol mSym : Syms){//mSym.getType()方法可以获取扫描的类型,ZBar支持多种扫描类型,这里实现了条形码、二维码、ISBN码的识别if (mSym.getType() == Symbol.CODE128 || mSym.getType() == Symbol.QRCODE || mSym.getType() == Symbol.CODABAR ||    mSym.getType() == Symbol.ISBN10 ||mSym.getType() == Symbol.ISBN13|| mSym.getType()==Symbol.DATABAR ||mSym.getType()==Symbol.DATABAR_EXP || mSym.getType()==Symbol.I25){//添加震动效果,提示用户扫描完成Vibrator mVibrator=(Vibrator)getSystemService(VIBRATOR_SERVICE);mVibrator.vibrate(400);Intent intent=new Intent(MainActivity.this,ResultActivity.class);intent.putExtra("ScanResult", "扫描类型:"+GetResultByCode(mSym.getType())+"\n"+ mSym.getData());//这里需要注意的是,getData方法才是最终返回识别结果的方法//但是这个方法是返回一个标识型的字符串,换言之,返回的值中包含每个字符串的含义//例如N代表姓名,URL代表一个Web地址等等,其它的暂时不清楚,如果可以对这个进行一个较好的分割//效果会更好,如果需要返回扫描的图片,可以对Image做一个合适的处理startActivity(intent);IsScanned = true;}else{//否则继续扫描IsScanned = false;mCamera.setPreviewCallback(previewCb);mCamera.startPreview();IsPreview = true;mCamera.autoFocus(autoFocusCB);}}}}};//用于刷新自动聚焦的方法AutoFocusCallback autoFocusCB = new AutoFocusCallback(){public void onAutoFocus(boolean success, Camera camera){mAutoFocusHandler.postDelayed(doAutoFocus, 1000);}};//根据返回的代码值来返回相应的格式化数据public String GetResultByCode(int CodeType){String mResult="";switch(CodeType){//条形码case Symbol.CODABAR:mResult="条形码";break;//128编码格式二维码)case Symbol.CODE128:mResult="二维码";break;//QR码二维码case Symbol.QRCODE:mResult="二维码";break;//ISBN10图书查询case Symbol.ISBN10:mResult="图书ISBN号";break;//ISBN13图书查询case Symbol.ISBN13:mResult="图书ISBN号";break;}return mResult;}}

对于显示扫描结果的界面,代码比较简单

/** 返回扫描结果* 作者:秦元培* 时间:2013年12月21日* 总结:这里有一个问题,就是在这个界面上按下返回键的时候程序会立即报错,试着重写过相关的方法都解决不了问题* 谁要是知道这个问题怎么解决,记得给我说一声啊*/
package com.Android.ZBar4Android;import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.TextView;public class ResultActivity extends Activity
{private TextView tv;private Button BtnBack;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.layout_result);//获取扫描结果Intent intent=getIntent();Bundle mData=intent.getExtras();CharSequence mResult=mData.getCharSequence("ScanResult");StringHelper mHelper=new StringHelper(mResult.toString());mResult=mHelper.SplitFormDict();tv=(TextView)findViewById(R.id.TextResult);tv.setText(mResult);//返回扫描界面BtnBack=(Button)findViewById(R.id.BtnBack);BtnBack.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View arg0) {Intent intent=new Intent(ResultActivity.this,MainActivity.class);startActivity(intent);}});}@Overrideprotected void onPause() {super.onPause();}}

五、总结

经过测试,可以快速地对二维码进行识别,并显示扫描结果。目前尚存在的问题有:

1、官方的文档说它是支持条形码、ISBN、二维码等多种形式的编码的,并且在程序代码中亦有所体现,但是实际测试中,发现二维码可以扫,其余的无法扫描

2、锁屏后再次打开程序会报错

3、与微信等类似的需要相机功能的软件冲突

4、校准框死活画不出来

5、在扫描结果界面下按下返回键,程序报错,无法拦截

欢迎大家积极寻找解决问题的方法,再次谢谢大家!

源代码下载

Android开发学习之基于ZBar实现微信扫一扫相关推荐

  1. (4.2.29) Android开发学习之基于ZBar实现微信扫一扫

    蛰伏半月有余,一直在准备期末考试,期间抽空研究了一些Android的源代码,现在我就把在这其中的一些收获分享给大家. 今天想分享给大家的是二维码扫描.说起二维码,大家一定不会陌生,尤其是微信火了以后, ...

  2. Android开发学习之基于ViewPager实现Gallery画廊效果

    通过我们前面的学习,我们知道ViewPager是可以做出近乎完美的滑动体验,回顾整个Android,我们发现Gallery具备同样的特点,于是我们大胆地猜想,Gallery是否和ViewPager之间 ...

  3. Android开发学习之以CameraAPI方式实现相机功能(一)——快速实现相机

    今天无意当中发现在<Android开发学习之基于ZBar实现微信扫一扫>中的一部分代码可以用来以硬件方式实现一个照相机的功能,在<Android开发学习之调用系统相机完成拍照的实现& ...

  4. android培训内容明细,记录Android开发学习

    记录Android开发学习 Menu菜单学习 1.掌握Android中菜单的创建. 2.掌握Intent信使组件. 创建菜单Menu 我们模仿微信菜单栏学习,创建一个于微信菜单栏相似的菜单 那么我们应 ...

  5. Android开发自学笔记(基于Android Studio1.3.1)—1.环境搭建(转)

    一.引言    本套学习笔记的开发环境是Windows 10 专业版和Android Studio 的最新版1.3.1. Android Studio 是一个Android开发环境,基于Intelli ...

  6. android开发用百度识别图片格式,Android开发学习之路-机器学习库(图像识别)、百度翻译...

    对于机器学习也不是了解的很深入,今天无意中在GitHub看到一个star的比较多的库,就用着试一试,效果也还行.比是可能比不上TensorFlow的,但是在Android上用起来比较简单,毕竟Tens ...

  7. 《Android Studio应用开发实战详解》——第1章,第1.5节Android开发学习路线图

    本节书摘来自异步社区<Android Studio应用开发实战详解>一书中的第1章,第1.5节Android开发学习路线图,作者 王翠萍,更多章节内容可以访问云栖社区"异步社区& ...

  8. Android开发自学笔记(基于Android Studio1.3.1)—1.环境搭建

    一.引言 本套学习笔记的开发环境是Windows 10 专业版和Android Studio 的最新版1.3.1. Android Studio 是一个Android开发环境,基于IntelliJ I ...

  9. android开发学习大体思路

    android开发学习: android学习的前提是java基础.如果你没有好的java基础,那就赶紧补充,我在这里不做介绍. android是基于linux的,如果你要做底层的东西,可以买一些关于l ...

最新文章

  1. 高性能服务器编程代码清单9-3,JRockit JVM优化清单/调优指南
  2. php的Traits属性以及基本用法
  3. 性别分析--微信数据分析(一)
  4. Hit or Miss
  5. 08.认证考试注意事项
  6. [转] ArcEngine 产生专题图
  7. P7990-[USACO21DEC]Closest Cow Wins S【堆,贪心】
  8. C# 多线程编程 ThreadStart ParameterizedThreadStart
  9. flannel无法跨主机ping通容器的解决方式
  10. python 读取excel太慢_实用技巧——Python实现从Excel读取数据并绘制成图像
  11. python手机版下载-qpython手机版下载
  12. 多路搜索树的初始化实现
  13. 10部顶级数学纪录片
  14. 初中计算机表格知识点,初中信息技术考试知识点.doc
  15. 毕业设计,基于语音控制的智能家居控制系统
  16. 机器学习应用——强化学习课程总结 实例 “自主学习Flappy Bird游戏”(MDP蒙特卡洛强化学习Q-learningDRLDQN)
  17. Leetcode刷题笔记12:【20】有效的括号【155】最小栈【255】用队列实现栈(STL:stackC++ 单引号和双引号)
  18. Balsamiq Mockups 便携版
  19. java自定义font_java – 设置自定义字体
  20. golang data race 竞态条件

热门文章

  1. 浅析企业网络准入控制系统的部署方式
  2. 联想微型计算机620S,小巧、精致!联想ideacenter 620s远不止如此
  3. 我的Go+语言初体验——初学者的快速入门
  4. win11怎么共享文件夹 Windows11共享文件夹的设置方法
  5. selenium - 操作 DropDown 下拉表 (以微博注册为例)
  6. windows 10, v1903 正式版下载
  7. Demo:校验_SAP刘梦_新浪博客
  8. 工具篇:Git与Github+GitLib常用操作(不定期持续更新)
  9. 怎么投稿各大媒体网站?有哪些媒体网站?
  10. 2019-6-27-WPF-如何给定两个点画出一条波浪线