首页 文章 精选 留言 我的

精选列表

搜索[扩展层],共10009篇文章
优秀的个人博客,低调大师

弹出式菜单扩展学习

看其它应用软件时使用了很多的弹出菜单,蛮好的,顺带学习了下,写了个小DEMO,里面穿插的讲了下系统级的dialog使用小巧门,希望与大家交流学习。。下面来看代码: packagecom.xiaoma.popupmenu.demo; importandroid.app.Activity; importandroid.app.Dialog; importandroid.app.ProgressDialog; importandroid.os.Bundle; importandroid.util.Log; importandroid.view.MenuInflater; importandroid.view.MenuItem; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; importandroid.widget.PopupMenu; importandroid.widget.Toast; importandroid.widget.PopupMenu.OnMenuItemClickListener; /** *@Title:PopupMenuDemoActivity.java *@Packagecom.xiaoma.popupmenu.demo *@Description:弹出式菜单测试类 *@authorMZH */ publicclassPopupMenuDemoActivityextendsActivityimplementsOnClickListener,OnMenuItemClickListener{ privateButtonshow; /**Calledwhentheactivityisfirstcreated.*/ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); init(); } /* *初始化实现 */ privatevoidinit(){ show=(Button)findViewById(R.id.button1); show.setOnClickListener(this); } /* *添加监听器(non-Javadoc) *@seeandroid.view.View.OnClickListener#onClick(android.view.View) */ @Override publicvoidonClick(Viewv){ if(v.getId()==R.id.button1){ showPopup(v); } } /* *弹出对话框实现 */ privatevoidshowPopup(Viewv){ PopupMenupopup=newPopupMenu(getApplicationContext(),v); popup.setOnMenuItemClickListener(this); MenuInflaterinflater=popup.getMenuInflater(); inflater.inflate(R.menu.menutest,popup.getMenu()); popup.show(); } /* *给选择的项添加监听器(non-Javadoc) */ @Override publicbooleanonMenuItemClick(MenuItemitem){ switch(item.getItemId()){ caseR.id.new_game: Log.i("KKK","奇怪"); ShowDialog(item.getTitle()); break; caseR.id.help: ShowDialog(item.getTitle()); break; caseR.id.file: ShowDialog(item.getTitle()); break; caseR.id.create_new: ShowDialog(item.getTitle()); break; caseR.id.open: ShowDialog(item.getTitle()); break; default: break; } returnfalse; } /* *弹出消息方法实现 *因为安卓系统中也自带这样一个临时弹出dialog的方法 *showDialog(intid),所以小马在此处违背了下一般的命名 *规则,起名:ShowDialog(),下面顺带讲下系统自带的临时dialog的实现 */ privatevoidShowDialog(CharSequencech){ Toast.makeText(getApplicationContext(),ch,Toast.LENGTH_SHORT).show(); } /** *在使用系统级自带的showDialog(intid)方法时,必须重载下面这个方法哦 */ @Override protectedDialogonCreateDialog(intid){ ProgressDialogdialog=newProgressDialog(this); dialog.setMessage("小马临时放的字符串一"); returndialog; } /** *在使用系统级自带的showDialog(intid,intid,Bundleargs)方法时, *必须重载下面这个方法 *id:dialog的ID *args为提供给showDialog的第二个方法 */ @Override protectedDialogonCreateDialog(intid,Bundleargs){ ProgressDialogdialog=newProgressDialog(this); dialog.setMessage("小马临时放的字符串二"); returndialog; } } 加载的菜单布局如下: <?xmlversion="1.0"encoding="utf-8"?> <menuxmlns:android="http://schemas.android.com/apk/res/android"> <itemandroid:id="@+id/new_game" android:icon="@drawable/ic_launcher" android:title="新游戏" android:showAsAction="ifRoom"/> <itemandroid:id="@+id/help" android:icon="@drawable/ic_launcher" android:title="帮助"/> <itemandroid:id="@+id/file" android:title="嵌套"> <menu> <itemandroid:id="@+id/create_new" android:title="开始新游戏"/> <itemandroid:id="@+id/open" android:title="开始"/> </menu> </item> <groupandroid:id="@+id/group_delete"> <itemandroid:id="@+id/menu_archive" android:title="组员一"/> <itemandroid:id="@+id/menu_delete" android:title="组员二"/> </group> </menu> 很简单的实现,每天进步一点点,吼吼。。学习再学习!加油。。。 附件:http://down.51cto.com/data/2359943 本文转自华华世界 51CTO博客,原文链接:http://blog.51cto.com/mzh3344258/791569,如需转载请自行联系原作者

优秀的个人博客,低调大师

c#扩展出MapReduce方法

MapReduce方法主体: 1 public static IDictionary<TKey, TResult> MapReduce<TInput, TKey, TValue, TResult>(this IList<TInput> inputList, 2 Func<MapReduceData<TInput>, KeyValueClass<TKey, TValue>> map, Func<TKey, IList<TValue>, TResult> reduce) 3 { 4 object locker = new object(); 5 ConcurrentDictionary<TKey, TResult> result = new ConcurrentDictionary<TKey, TResult>(); 6 //保存map出来的结果 7 ConcurrentDictionary<TKey, IList<TValue>> mapDic = new ConcurrentDictionary<TKey, IList<TValue>>(); 8 var parallelOptions = new ParallelOptions(); 9 parallelOptions.MaxDegreeOfParallelism = Environment.ProcessorCount; 10 //并行map 11 Parallel.For(0, inputList.Count(), parallelOptions, t => 12 { 13 MapReduceData<TInput> data = new MapReduceData<TInput> 14 { 15 Data = inputList[t], 16 Index = t, 17 List = inputList, 18 }; 19 var pair = map(data); 20 if (pair != null && pair.Valid) 21 { 22 //锁住防止并发操作list造成数据缺失 23 lock (locker) 24 { 25 //将匹配出来的结果加入结果集放入字典 26 IList<TValue> list = null; 27 if (mapDic.ContainsKey(pair.Key)) 28 { 29 list = mapDic[pair.Key]; 30 } 31 else 32 { 33 list = new List<TValue>(); 34 mapDic[pair.Key] = list; 35 } 36 list.Add(pair.Value); 37 } 38 } 39 }); 40 41 //并行reduce 42 Parallel.For(0, mapDic.Keys.Count, parallelOptions, t => 43 { 44 KeyValuePair<TKey, IList<TValue>> pair = mapDic.ElementAt(t); 45 result[pair.Key] = reduce(pair.Key, pair.Value); 46 }); 47 return result; 48 } View Code KeyValueClass定义: 1 public class KeyValueClass<K, V> 2 { 3 public KeyValueClass(K key, V value) 4 { 5 Key = key; 6 Value = value; 7 } 8 9 public KeyValueClass() 10 { 11 12 } 13 14 public K Key { get; set; } 15 16 public V Value { get; set; } 17 } View Code Console测试: 1 List<TestClass> listTestClass = new List<TestClass>(); 2 listTestClass.Add(new TestClass { a = "a", g = 1 }); 3 listTestClass.Add(new TestClass { a = "b", g = 3 }); 4 listTestClass.Add(new TestClass { a = "c", g = 4 }); 5 listTestClass.Add(new TestClass { a = "d", g = 2 }); 6 listTestClass.Add(new TestClass { a = "e", g = 1 }); 7 listTestClass.Add(new TestClass { a = "f", g = 2 }); 8 listTestClass.Add(new TestClass { a = "g", g = 5 }); 9 listTestClass.Add(new TestClass { a = "h", g = 6 }); 10 IDictionary<int, string> dic = listTestClass.MapReduce(t => 11 { 12 if (t.g < 5) 13 { 14 return new KeyValueClass<int, string>(t.g, t.a); 15 } 16 return null; 17 }, (key, values) => 18 { 19 return string.Join(",", values); 20 }); View Code TestClass定义: 1 public class TestClass 2 { 3 public string a { get; set; } 4 public string b { get; set; } 5 6 public string d { get; set; } 7 8 //public DateTime f { get; set; } 9 10 public int g { get; set; } 11 12 public List<TestClass> test { get; set; } 13 14 public Dictionary<string, string> dic { get; set; } 15 } View Code 结果: 1:a,e 2:d,f 3:b 4:c 词频性能测试

优秀的个人博客,低调大师

鸿蒙系统框架层的启动细节

本文可看做是前文《鸿蒙系统的启动流程v2.0》的第四阶段的补充和验证。 首先请看我的环境:HiSpark AI Camera开发板(Hi3516dv300) + DevEco的HPM新建工程[Hi3516]编译的软件,项目代码默认打印的大部分log被我临时关掉了,按我自己的风格在关键点重新打印的log,log基本样例为: [system_init] SystemInit[20-18]: system_console_init[full shell]:[system_init] //在system_init.c 文件内: SystemInit[20-18] //在SystemInit()函数内,大概有20步主要动作,这是第18步:system_console_init[full shell] //这一步做了哪些事,或者打印关键信息 附件的log,是我在Hi3516开发板上抓的,大概从内核创建 Init 进程前一点点,到系统启动稳定的全过程,最后一段是点击相机应用打开摄像头的log。我将其分成若干段,下面一步步分析其启动细节。 1. 创建 /bin/init 前:Line3~7 [system_init] SystemInit[20-18]: system_console_init[full shell][system_init] system_console_init()->OsShellInit() [system_init] SystemInit[20-20]: OsUserInitProcess() Create user init process[run /bin/init] 前面的SystemInit()步骤,请自行阅读代码理解。从 system_console_init()进去跟踪,可以确认跑的是 Hi3516/kernel/liteos_a/shell/full/ 里面的代码,而不是 Hi3516/kernel/liteos_a/apps/shell/ 里面的简化版的shell。这个可以从后面启动shell服务时打印的“OHOS # ”可以确认,full shell会打印这个,apps的shell不会打印。然后就是创建用户根进程 Init,并切换到用户态去跑 /bin/init 程序了。 2. /bin/init :Line10~27 + Line180~182 [init_lite] "/bin/init" main: starting OHOS Framework.........[init_lite] main[4-3] enter: InitReadCfg()...... Line180~182: [init_cmds] DoChown, failed for 0 99 /dev/hdfwifi, err 2. [init_lite] main[4-4] enter: while(1)... 这是 Hi3516/base/startup/services/init_lite/src/main.c 里的main函数跑的流程。【至于内核态进程怎么切换到用户态来跑这个函数,详情可阅读前文《鸿蒙系统的启动流程v2.0》的第三阶段的分析】从这里开始到下面的 Line180~182,中间部分都是 DoJob()三个阶段做的工作,我们先主要关注init阶段的start service部分。 下面要依次启动的服务,见 /Hi3516/vendor/huawei/camera/init_configs/init_liteos_a_3516dv300.cfg 文件: { "name" : "init", "cmds" : [ "start shell", "start apphilogcat", "start foundation", "start bundle_daemon", "start appspawn", "start media_server", "start wms_server" ] } 3. start shell :Line29~31 [init_service] ServiceStart [[shell]] succeed, pid = 3. OHOS # 如上所述,代码在 Hi3516/kernel/liteos_a/shell/full/ 具体入口函数是哪个,我没去找,感兴趣的朋友自行找一下。在开发板跑起来之后就已经开启shell服务了,在DevEco的monitor下敲个回车键就可以一看到“OHOS #”,敲个 task 命令看一下。需要注意的是,debug版本才会提供shell功能,release版本不提供,会 start service fail。 4.start apphilogcat :Line33~35 [init_service] ServiceStart [[apphilogcat]] succeed, pid = 4. [hiview_applogcat] main entering while(1)... 这是DFX子系统的logcat服务,入口见:Hi3516/base/hiviewdfx/services/hilogcat_lite/apphilogcat/hiview_applogcat.c 文件内的 main()。函数一开始就: if (argc == 1) { #ifdef OHOS_RELEASE return 0; #endif } 也就是debug版本才会提供logcat功能,release版本不提供。服务会进入while(1)循环,等待条件出现,将log打印到终端和文件内。 ret = read(fd, buf, HILOG_LOGBUFFER); if (ret < sizeof(struct HiLogEntry)) { continue; } 这就是条件,意味着几乎每条log都会打印到终端,也会打印到文件里去,频繁的文件读写操作,不可避免会影响系统性能(流畅性/稳定性),这就是为什么不建议普通用户升级开发版的鸿蒙系统作为日常使用的原因之一。 另外,DFX子系统,还有一个logcat服务,不过看起来并没有启动起来:Hi3516/base/hiviewdfx/services/hilogcat_lite/hilogcat/hiview_logcat.c这个服务只提供log打印到终端功能,而上面的apphilogcat则是log除了打印到终端外,同时还会保存到磁盘文件中。 5.start foundation: Line38~86 这个服务的启动要重点讲一下。入口在: Hi3516/foundation/distributedschedule/services/safwk_lite/src/main.c在真正的 foundation 服务启动 [safwk_lite:main] Foundation server begin: 之前,会先打印一大段 SERVICE_INIT 和 FEATURE_INIT 的log: ???????????????????????????????????????????????????????????????????? [samgr_server] SYS_SERVICE_INIT(InitializeRegistry)# **samgr**: g_server [samgr_lite] SAMGR_GetInstance(mutex=NULL): NO SAMGR instance, Init() to create ONE [samgr_lite] Init. mutex[664156832]. sharedPool[0-8] reset to 0. status=0[BOOT_SYS] [samgr_lite] SAMGR_GetInstance(mutex=664156832) [permission_service] APP_SERVICE_INIT(Init) # permissionms [ipc_auth_lite] APP_FEATURE_INIT(Init) : ipc_auth [pms_inner] APP_FEATURE_INIT(Init) : PmsInner [pms_server] APP_FEATURE_INIT(Init) : PmsFeature [ability_mgr_service] SYSEX_SERVICE_INIT(Init)# abilityms [ability_mgr_feature] SYSEX_FEATURE_INIT(Init): AmsFeature [ability_inner_feature] SYSEX_FEATURE_INIT(Init): AmsInnerFeature [bundle_ms_host] APP_SERVICE_INIT(Init) # bundlems [bundle_inner_feature] APP_FEATURE_INIT(Init) : BmsInnerFeature [bundle_ms_feature] APP_FEATURE_INIT(Init) : BmsFeature [distributed_schedule_service] SYS_SERVICE_INIT(Init) # dtbschedsrv [dmslite] SYS_FEATURE_INIT(Init) : dmslite ???????????????????????????????????????????????????????????????????? 为什么呢? 一开始我也是很多问号,Hi3861平台上,会跑 HOS_SystemInit() void HOS_SystemInit(void) { MODULE_INIT(bsp); MODULE_INIT(device); MODULE_INIT(core); SYS_INIT(service); SYS_INIT(feature); MODULE_INIT(run); SAMGR_Bootstrap(); } 以此来启动相关的service/feature以及app上标记为 SYS_RUN()的应用,但是Hi3516上并没有跑上面这个函数,而是跑弱引用的OHOS_SystemInit(): void __attribute__((weak)) OHOS_SystemInit(void) { SAMGR_Bootstrap(); } 我就到 Hi3516/foundation/distributedschedule/services/safwk_lite/ 目录下去看 foundation 进程相关的 README.md,内容很丰富,但貌似没有合理的解释。那就再到 OHOS1_1_0LTS/foundation/distributedschedule/safwk_lite/ 目录下去看 README_zh.md,这回有点意思了。 safwklite模块负责提供基础服务运行的空进程。safwklite是foundation进程的实现。在foundation进程中添加服务,按照服务的模板写完服务后在BUILD.gn中添加依赖即可。 虽然只有简短的几句话,但意思很明确了:a.foundation是一个空进程,但是它“负责提供基础服务运行”b.服务(基础服务或者开发者新增的服务)要运行起来,需要按模板添加在safwklite的BUILD.gn依赖中所以,打开safwklite的BUILD.gn看一下依赖关系: deps = [ "//foundation/distributedschedule/services/samgr_lite/samgr_server:server", "//base/hiviewdfx/frameworks/hilog_lite/featured:hilog_shared", "//base/security/services/iam_lite/ipc_auth:ipc_auth_target", ] if (ohos_kernel_type == "liteos_a") { deps += [ "//base/security/services/iam_lite/pms:pms_target", "//foundation/aafwk/services/abilitymgr_lite:abilityms", "//foundation/appexecfwk/services/bundlemgr_lite:bundlems", "//foundation/distributedschedule/services/dtbschedmgr_lite:dtbschedmgr", ] } 所以上面那一大段 SERVICE_INIT 和 FEATURE_INIT 的log中,会先分别按顺序启动几个service(用'#'标记):samgr/permissionms/abilityms/bundlems/dtbschedsrv,这是服务的名字,真正的组件名字就分别是:samgr_lite/iam_lite/abilitymgr_lite/bundlemgr_lite/dtbschedmgr_lite。samgr_lite 组件提供了分布式任务管理和调度能力,其他所有的系统能力都由它管理和调度【简单的分析见前文《理解启动恢复子系统》 的5.3小节,未来会单独写文章对SAMGR进行详细分析,敬请期待】。另外四个组件,又包含各自的feature,会在这里一并进行init/注册和提供服务(用':'标记)【进一步的细节,请自行去分析相关的BUILD.gn文件】。如README.md所说,以后开发者要是开发了新的服务或者feature,都可以添加在foundation的依赖关系中。所以,这里的foundation,实际上做的就是上面Hi3861平台中的SYS_INIT(service) 和 SYS_INIT(feature) 两步所做的工作。 Line60~86:这就是调用SAMGR_Bootstrap()来注册上面的几个服务的具体流程了,这里先略过,详情请自行阅读代码进行跟踪和分析。 Line88~100:这里是 dmslite 这个 feature 开始向软总线发布dms服务了: [dmslite] OnInitialize(): PublishService(dms)-->>softbus......[dmslite_session] CreateSessionServer(moduleName[dms], sessionName[dms])[dmslite] OnPublishSuccess(publishId[1]), CreateSessionServer() 这就开始涉及到分布式软总线子系统了。刚好上周我在Hi3861平台上对软总线做了一番研究和调试,对此有了一点了解,为了避免软总线的log对本文分析的流程的影响,我也暂时把软总线的log关闭了,Hi3516和Hi3861工程都可以在foundation/communication/services/softbus_lite/os_adapter/include/os_adapter.h 找到 SOFTBUS_DEBUG 这个宏,def 或者 undef就可以打开/关闭软总线的log了。对于软总线子系统的理解,我会另文专门分析总结,敬请期待。 6.start bundle_daemon: Line108~128 包管理服务的启动,暂未进一步分析。入口在:Hi3516/foundation/appexecfwk/services/bundlemgr_lite/bundle_daemon/src/bundle_daemon.cpp 7.start appspawn: Line132~157 启动appspawn应用孵化器服务,入口在: /Hi3516/base/startup/services/appspawn_lite/src/appspawn_service.c这是所有应用程序进程的父进程,appspawn通过接收应用程序框架的命令来孵化应用进程,具体流程这里也不做进一步深入了,请自行阅读代码进行分析。 8.start media_server: Line161~165 启动媒体服务,入口在:Hi3516/foundation/multimedia/services/media_lite/media_main.cpp提供播放、录制、解析、解码等接口能力,并提供媒体播放录制引擎服务化能力。 [/third_party/iniparser/src/iniparser.c] iniparser_load(/storage/data/cameradev.ini) 这里会调用三方库来分析cameradev.ini文件(Hi3516/applications/sample/camera/media/cameradev_imx335.ini 的副本),获取摄像头sensor的配置信息。 9.start wms_server: Line169~223 启动图形WMS组件服务,暂未进一步分析。入口在: Hi3516/foundation/graphic/lite/services/wms/src/server/samgr_wms.cpp图形服务采用C/S架构,内部分为窗口管理(WMS: Window Manager Service)和输入事件管理(IMS: Input Manger Service)两个子服务。 10.[appspawn_service] Invoke(): Line226~ 这里就是 appspawn 开始孵化第一个应用launcher,也就是我们看到的桌面。 [appspawn_service] Invoke()[appspawn_service] Invoke: msg:: bundleName[com.huawei.launcher],sharedLibPaths[],identityID[73014444033],uID[101],gID[101] 再接下来的我点击相机应用图标,启动摄像头,也有一段log [appspawn_service] Invoke()[appspawn_service] Invoke: msg:: bundleName[com.huawei.camera],sharedLibPaths[],identityID[661424963587],uID[100],gID[100] 附件是完整的log,能理解多少就看各位的造化了~.~。感谢阅读。 文章相关附件可以点击下面的原文链接前往学习 原文链接:https://harmonyos.51cto.com/posts/4498#bkwz 想了解更多关于鸿蒙的内容,请访问: 51CTO和华为官方战略合作共建的鸿蒙技术社区 https://harmonyos.51cto.com/#bkwz

优秀的个人博客,低调大师

Android应用开发—RecyclerView绘制蒙层

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/voidreturn/article/details/77718470 背景:如何在跨越两个或两个以上的item绘制一个view,该view需要跟随recyclerView的滑动而整体移动。 @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDrawOver(c, parent, state); final View child = parent.getChildAt(1); if (child != null) { final int left = child.getLeft(); final int right = child.getRight(); final int top = child.getTop(); final int bottom = child.getBottom(); int rightV = (right - left) / 6; int leftV = (right - rightV) - VAUtils.dip2px(mContext, 225); int topV = bottom - VAUtils.dip2px(mContext, 16); int bottomV = topV + VAUtils.dip2px(mContext, 82); ViewGroup.MarginLayoutParams margin = new ViewGroup.MarginLayoutParams(mImageView.getLayoutParams()); margin.setMargins(leftV, topV, rightV, bottomV); RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(margin); mImageView.setLayoutParams(layoutParams); if (!imageClicked) { mImageView.setVisibility(View.VISIBLE); } //画笔 final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); //圆心 x 坐标 final float x = parent.getWidth() / 2 + left; ////圆心 y 坐标 final float y = 100 + top; //半径 final float radius = 100; //渐变着色器 坐标随意设置的 final LinearGradient shader = new LinearGradient(x-50, 0, x+100, 200, Color.RED, Color.YELLOW, Shader.TileMode.REPEAT); paint.setShader(shader); //绘制圆 c.drawCircle(x, y, radius, paint); } } @Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDrawOver(c, parent, state); //画笔 final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); //圆心 x 坐标 final float x = parent.getWidth() / 2; ////圆心 y 坐标 final float y = 100; //半径 final float radius = 100; //渐变着色器 坐标随意设置的 final LinearGradient shader = new LinearGradient(x-50, 0, x+100, 200, Color.RED, Color.YELLOW, Shader.TileMode.REPEAT); paint.setShader(shader); //绘制圆 c.drawCircle(x, y, radius, paint); }

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册