首页 文章 精选 留言 我的

精选列表

搜索[人设自定义],共10000篇文章
优秀的个人博客,低调大师

在XML drawable中引用自定义颜色

= 先看一下一个xml drawable文件,这是一个button的样式。 <?xml version="1.0" encoding="utf-8" ?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" > <shape> <solid android:color="#FB7C16" /> <stroke android:width="1dp" android:color="#FB7C16" /> <corners android:radius="3dp" /> </shape> </item> <item> <shape> <solid android:color="#1FAC75"/> <stroke android:width="1.0dp" android:color="#1FAC75" /> <corners android:radius="3dp" /> </shape> </item> </selector> 可以看到这里好几处用到了颜色,但是都是直接指定颜色值,如果我想引用一个外部颜色,比如定义在values/refs里面的。那该怎么办呢? 先在values/refs.xml文件里面定义颜色,如下: <?xml version="1.0" encoding="utf-8"?> <resources> <drawable name="whitecolor">#FFFFFF</drawable> <drawable name="blackcolor">#000000</drawable> <drawable name="graycolor">#aaaaaa</drawable> <drawable name="drawerdivider">#FFFFFF</drawable> <!--<drawable name="theme_color">#1FAC75</drawable>--> <drawable name="theme_color">#FF3300</drawable> <drawable name="search_page_color">#60D1A3</drawable> <drawable name="grid_background">#FFFDF1</drawable> <!--<color name="theme_color">#1FAC75</color>--> <color name="theme_color">#FF3300</color> </resources> 然后在drawable xml文件里面引用颜色即可,如下: </item> <item> <shape> <solid android:color="@color/theme_color"/> <stroke android:width="1.0dp" android:color="@color/theme_color" /> <corners android:radius="3dp" /> </shape> </item> </selector> 本文转自zdd博客园博客,原文链接:http://www.cnblogs.com/graphics/p/4704863.html,如需转载请自行联系原作者

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

Android自定义线程池的编程实战

1、Executor 简介 在Java 5之后,并发编程引入了一堆新的启动、调度和管理线程的API。Executor框架便是Java 5中引入的,其内部使用了线程池机制,它在java.util.cocurrent 包下,通过该框架来控制线程的启动、执行和关闭,可以简化并发编程的操作。因此,在Java 5之后,通过Executor来启动线程比使用Thread的start方法更好,除了更易管理,效率更好(用线程池实现,节约开销)外,还有关键的一点:有助于避免this逃逸问题——如果我们在构造器中启动一个线程,因为另一个任务可能会在构造器结束之前开始执行,此时可能会访问到初始化了一半的对象用Executor在构造器中。 Executor框架包括:线程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等。 在java代码中 Executor是一个接口,只有一个方法。 publicinterfaceExecutor{ /** *Executesthegivencommandatsometimeinthefuture.Thecommand *mayexecuteinanewthread,inapooledthread,orinthecalling *thread,atthediscretionofthe{@codeExecutor}implementation. * *@paramcommandtherunnabletask *@throwsRejectedExecutionExceptionifthistaskcannotbe *acceptedforexecution *@throwsNullPointerExceptionifcommandisnull */ voidexecute(Runnablecommand); } 2、ExecutorService ExecutorService 是一个接口,继承 Executor ,除了有execute( Runnable command) 方法外,还拓展其他的方法: publicinterfaceExecutorServiceextendsExecutor{ } void shutdown(); List<Runnable> shutdownNow(); boolean isShutdown(); boolean isTerminated(); boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException; <T> Future<T> submit(Callable<T> task); //提交一个任务 <T> Future<T> submit(Runnable task, T result); //提交一个任务 Future<?> submit(Runnable task); //提交一个任务 <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException; <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException; <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException; <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; 2.1 execute(Runnable) 接收一个 java.lang.Runnable 对象作为参数,并且以异步的方式执行它。如下是一个使用 ExecutorService 执行 Runnable 的例子 packagecom.app; importjava.util.concurrent.ExecutorService; importjava.util.concurrent.Executors; publicclassExecutorTest{ publicstaticvoidmain(String[]args){ //创建一个线程数固定大小为10的线程池 ExecutorServiceexecutorService=Executors.newFixedThreadPool(10); //执行一个任务该任务是newRunnable()对象 executorService.execute(newRunnable(){ @Override publicvoidrun(){ Log.d(Thread.currentThread().getName()); } }); //关闭线程池 executorService.shutdown(); } } 结果: pool-1-thread-1 使用这种方式没有办法获取执行 Runnable 之后的结果,如果你希望获取运行之后的返回值,就必须使用 接收 Callable 参数的 execute() 方法,后者将会在下文中提到。 2.2、submit(Runnable) 方法 submit(Runnable) 同样接收一个 Runnable 的实现作为参数,但是会返回一个 Future 对象。这个 Future 对象可以用于判断 Runnable 是否结束执行。如下是一个 ExecutorService 的 submit() 方法的例子: packagecom.app; importjava.util.concurrent.ExecutorService; importjava.util.concurrent.Executors; importjava.util.concurrent.Future; publicclassExecutorTest{ publicstaticvoidmain(String[]args){ //创建一个线程数固定大小为10的线程池 ExecutorServiceexecutorService=Executors.newFixedThreadPool(10); //执行一个任务该任务是newRunnable()对象 Futurefuture=executorService.submit(newRunnable(){ @Override publicvoidrun(){ Log.d(Thread.currentThread().getName()); } }); try{ //如果任务结束执行则返回null Log.d(""+future.get()); }catch(Exceptione){ e.printStackTrace(); } //关闭线程池 executorService.shutdown(); } } 结果: pool-1-thread-1 null 2.3 submit(Callable) 方法 submit(Callable) 和方法 submit(Runnable) 比较类似,但是区别则在于它们接收不同的参数类型。Callable 的实例与 Runnable 的实例很类似,但是 Callable 的 call() 方法可以返回壹個结果。方法 Runnable.run() 则不能返回结果。 Callable 的返回值可以从方法 submit(Callable) 返回的 Future 对象中获取。如下是一个 ExecutorService Callable 的例子: packagecom.app; importjava.util.concurrent.Callable; importjava.util.concurrent.ExecutorService; importjava.util.concurrent.Executors; importjava.util.concurrent.Future; publicclassExecutorTest{ publicstaticvoidmain(String[]args){ //创建一个线程数固定大小为10的线程池 ExecutorServiceexecutorService=Executors.newFixedThreadPool(10); //执行一个任务该任务是newCallable()对象 Futurefuture=executorService.submit(newCallable<String>(){ @Override publicStringcall()throwsException{ return"执行完了"; } }); try{ //如果任务结束执行则返回 Log.d("结果是:"+future.get()); }catch(Exceptione){ e.printStackTrace(); } //关闭线程池 executorService.shutdown(); } } 结果: 结果是: 执行完了 2.4、inVokeAny() 方法 invokeAny() 接收一个包含 Callable 对象的集合作为参数。调用该方法不会返回 Future 对象,而是返回集合中某一个 Callable 对象的结果,而且无法保证调用之后返回的结果是哪一个 Callable,只知道它是这些 Callable 中一个执行结束的 Callable 对象。如果一个任务运行完毕或者抛出异常,方法会取消其它的 Callable 的执行。 packagecom.app; importjava.util.ArrayList; importjava.util.List; importjava.util.concurrent.Callable; importjava.util.concurrent.ExecutionException; importjava.util.concurrent.ExecutorService; importjava.util.concurrent.Executors; publicclassExecutorTest{ publicstaticvoidmain(String[]args){ //创建一个线程数固定大小为10的线程池 ExecutorServiceexecutorService=Executors.newFixedThreadPool(10); List<Callable<String>>list=newArrayList<>(); //创建第一个Callable Callable<String>callable1=newCallable<String>(){ @Override publicStringcall()throwsException{ Log.d("callable1线程是:"+Thread.currentThread().getName()); return"执行完了callable1"; } }; //创建第二个Callable Callable<String>callable2=newCallable<String>(){ @Override publicStringcall()throwsException{ Log.d("callable2线程是:"+Thread.currentThread().getName()); return"执行完了callable2"; } }; list.add(callable1); list.add(callable2); try{ Stringresult=executorService.invokeAny(list); Log.d("结果是:"+result); }catch(InterruptedExceptione1){ e1.printStackTrace(); }catch(ExecutionExceptione1){ e1.printStackTrace(); } //关闭线程池 executorService.shutdown(); } } 结果: callable 1 线程是: pool-1-thread-1 callable 2 线程是: pool-1-thread-2 结果是: 执行完了 callable 2 总结: 1、可以看到 Callable 里面的call方法,都是在子线程中运行的, 2、 executorService.invokeAny( list ) ;返回值是任意一个 Callable 的返回值 。具体是哪一个,每个都有可能。 2.5、invokeAll() 方法 invokeAll() 会调用存在于参数集合中的所有 Callable 对象,并且返回一个包含 Future 对象的集合,你可以通过这个返回的集合来管理每个 Callable 的执行结果。需要注意的是,任务有可能因为异常而导致运行结束,所以它可能并不是真的成功运行了。但是我们没有办法通过 Future 对象来了解到这个差异。 packagecom.app; importjava.util.ArrayList; importjava.util.List; importjava.util.concurrent.Callable; importjava.util.concurrent.ExecutorService; importjava.util.concurrent.Executors; importjava.util.concurrent.Future; publicclassExecutorTest{ publicstaticvoidmain(String[]args){ //创建一个线程数固定大小为10的线程池 ExecutorServiceexecutorService=Executors.newFixedThreadPool(10); List<Callable<String>>list=newArrayList<>(); //创建第一个Callable Callable<String>callable1=newCallable<String>(){ @Override publicStringcall()throwsException{ Log.d("callable1线程是:"+Thread.currentThread().getName()); return"执行完了callable1"; } }; //创建第二个Callable Callable<String>callable2=newCallable<String>(){ @Override publicStringcall()throwsException{ Log.d("callable2线程是:"+Thread.currentThread().getName()); return"执行完了callable2"; } }; list.add(callable1); list.add(callable2); List<Future<String>>result; try{ result=executorService.invokeAll(list); for(Future<String>future:result){ Log.d("结果是:"+future.get()); } }catch(Exceptione){ e.printStackTrace(); } //关闭线程池 executorService.shutdown(); } } 结果 callable 1 线程是: pool-1-thread-1 callable 2 线程是: pool-1-thread-2 结果是: 执行完了 callable 1 结果是: 执行完了 callable 2 注意:1:Callable 的call方法都是执行在子线程中的 2: executorService.invokeAll( list ) 是返回值。 但是必须是所有的 Callable对象执行完了,才会返回,返回值是一个list, 顺序和 List<Callable>一样 。在执行的过程中,如果任何一个Callable发生异常,程序会崩溃,没有返回值。 2.6 如何关闭 ExecuteService 服务 ? 当使用 ExecutorService 完毕之后,我们应该关闭它,这样才能保证线程不会继续保持运行状态。 举例来说,如果你的程序通过 main() 方法启动,并且主线程退出了你的程序,如果你还有一个活动的 ExecutorService 存在于你的程序中,那么程序将会继续保持运行状态。存在于 ExecutorService 中的活动线程会阻Java虚拟机关闭。 为了关闭在 ExecutorService 中的线程,你需要调用 shutdown() 方法。ExecutorService 并不会马上关闭,而是不再接收新的任务,一旦所有的线程结束执行当前任务,ExecutorServie 才会真的关闭。所有在调用 shutdown() 方法之前提交到 ExecutorService 的任务都会执行。 如果你希望立即关闭 ExecutorService,你可以调用 shutdownNow() 方法。这个方法会尝试马上关闭所有正在执行的任务,并且跳过所有已经提交但是还没有运行的任务。但是对于正在执行的任务,是否能够成功关闭它是无法保证 的,有可能他们真的被关闭掉了,也有可能它会一直执行到任务结束。这是一个最好的尝试。 作者:赵彦军 来源:51CTO

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

自然预言处理及自定义情绪分析

就在不久之前,大家都赌定飞行汽车和拟人机器人在2014年之前就会出现。 现在可以确定的是,飞行汽车的幻想破灭了,机器人也没能达到人们预想的样子。但是人类却实现了可以理解语言的“人工智能技术”。 这有点吓人?听起来似乎是的。但在笔者看来更多的是酷酷的感觉。 当人工智能语言被用来理解人类语言时,我们称(这种技术)为“自然语言处理”(NLP)。大多数用来解析文本的NLP引擎都带有一项叫做“情绪分析”的功能。通过该技术,我们可以知道一段文本带有正面,负面或是中性的情绪。 好的NLP引擎会将每一个词或短语标注情绪。举例来说,“糟糕的”就是一个带有负面情绪的词,而“美味的”则是正面情绪词。“蓝色的椅子”则是一个中性词。 情绪分析同时也会告诉我们一整段文字的属性。举例来说,如果一条微博说:“服务很差劲,但食物却很美味。”那么它会被认为是中性的。这是因为一

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

基于自定义日志打印的UDAF调试

看到最近有一些用户,代码在本地IDE环境里调试成功了后,到线上调试出现结果不符合预期的情况。因为IDE里无法模拟多个worker进行分布式调试UDAF的场景,所以有一些BUG可能需要到线上用一些简单的测试数据进行调试。这里用最简单的手工打印日志的方法,针对代码调试中最麻烦的UDAF的例子做一次调试。通过问题的定位和解决,希望能给大家在面对UDF的线上调试的时候提供一些思路。 初始化 首先,线上的真实数据可能非常多,千万不要直接对着上亿条数据直接调试,否则很难定位到原因。面对线上的问题,最好先根据数据情况,简化计算场景。比如我这里,就先把测试数据简化成: drop table if exists testUDAF; create table testUDAF( str string ) partitioned by (ds str

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

zabbix自定义脚本实现短信报警提醒

一 简介 通常,在zabbix的web界面配置好之后为了能够及时收到zabbix的报警信息,我们需要配置“报警媒介”来通知我们。其中常用的两种报警媒介分别是:Email和SMS,即:发邮件通知和发短信通知 关于邮件通知的配置很简单,只需要设置SMTP即可,因此这里不多说。但是zabbix默认的短信通知可就有点坑了,“SMS”这种报警媒介要想发送短信是需要硬件支持的。与此同时,现在开发中为了方便一般都是将短信发送的操作封装成接口的形式的,当需要发短信时只需要调用该接口同时传入收件人、短信详情等信息就可以完成一条短信的发送了 因此,为了简化zabbix短信通知的成本,我们可以考虑让zabbix调用外部的脚本请求短信接口来实现短信发送的功能 实现思路: 使用一个短信接口写一个发短信的脚本 在web界面中创建一个触发器,当问题严重性在“一般严重”及以上时执行上面的脚本,从而触发短信报警 二 具体实现步骤 (1)添加两个脚本(PS:发送短信脚本,并且是在zabbix_server上添加): [root@nmp01scripts]#cd/usr/local/zabbix [root@nmp01scripts]#cdmkdirscripts [root@nmp01scripts]#vim/usr/local/zabbix/scripts/sendsms.py 其内容是: #!/usr/bin/python #coding:utf-8 URL='http://192.168.150.2:8075/xxxx/wmgw.asmx' importsys importurllib importurllib2 importtime defsendsms(mobile,content): content='[%s]%s'%(time.strftime('%Y%m%d%H:%M:%S'),content) data='<soap:Envelopexmlns:soap="http://www.w3.org/2003/05/soap-envelope"xmlns:tem="http://tempuri.org/">......<tem:pszMobis>'+mobile+'</tem:pszMobis><tem:pszMsg>'+content+'</tem:pszMsg>.......</soap:Envelope>' #body=urllib.urlencode(data) request=urllib2.Request(URL,data) urldata=urllib2.urlopen(request) #printurldata.read() if__name__=='__main__': sendsms(sys.argv[1],sys.argv[2]) 注:这个Python脚本是一个实际的短信发送接口,为了去敏感话因此在data里省略了大量的内容。同时这个脚本需要从外部接收的参数是手机号和短信内容 [root@nmp01scripts]#vim/usr/local/zabbix/scripts/send.sh 其内容是: #!/bin/sh mobiles=(1581234120413876541234) messages="" foriin$@;do messages=$messages$i"" done formin${mobiles[@]}; do ./sendsms.py$m"$messages" done 注:这个脚本主要是通过循环遍历的形式控制到底给哪些用户发送短信,手机号放在“mobiles”数组中。脚本通过遍历参数当做短信内容,然后通过上面的sendsms.py发送短信 给脚本添加可执行权限: [root@nmp01scripts]#chmoda+x/usr/local/zabbix/scripts/* (2)配置zabbix_server的Web站点: 注:在“动作”里选择右上角的“事件源”时需要选择“触发器” 在这里不选择“发送消息”而是“执行命令”,其命令就是执行上面的脚本,也就是: cd/usr/local/zabbix/scripts ./send.sh"{TRIGGER.STATUS},服务器:{HOSTNAME1}发生:{TRIGGER.NAME}故障" 到此zabbix短信报警的配置就全部结束了,亲测可以正常收到短信,这里就不截图了 注:此种方式下,不需要再配置“报警媒介配置”以及用户的“报警媒介” PS:上面图片中的水印是我个人博客的域名,因此还请管理员手下留情不要给我标为“转载文章”,谢谢!!!

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

GMap.Net开发之自定义Marker

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using GMap.NET; using GMap.NET.WindowsForms; using GMap.NET.MapProviders; using GMap.NET.WindowsForms.Markers; namespace GMapWinFormDemo { public partial class MainForm : Form { private GMapOverlay objects = new GMapOverlay("objects"); //放置marker的图层 private GMapMarkerImage currentMarker; private bool isLeftButtonDown = false; private Timer blinkTimer = new Timer(); public MainForm() { InitializeComponent(); try { System.Net.IPHostEntry e = System.Net.Dns.GetHostEntry("ditu.google.cn"); } catch { mapControl.Manager.Mode = AccessMode.CacheOnly; MessageBox.Show("No internet connection avaible, going to CacheOnly mode.", "GMap.NET Demo", MessageBoxButtons.OK, MessageBoxIcon.Warning); } mapControl.CacheLocation = Environment.CurrentDirectory + "\\GMapCache\\"; //缓存位置 mapControl.MapProvider = GMapProviders.GoogleChinaMap; //google china 地图 mapControl.MinZoom = 2; //最小比例 mapControl.MaxZoom = 17; //最大比例 mapControl.Zoom = 5; //当前比例 mapControl.ShowCenter = false; //不显示中心十字点 mapControl.DragButton = System.Windows.Forms.MouseButtons.Left; //左键拖拽地图 mapControl.Position = new PointLatLng(32.064,118.704); //地图中心位置:南京 mapControl.OnMapZoomChanged += new MapZoomChanged(mapControl_OnMapZoomChanged); mapControl.MouseClick += new MouseEventHandler(mapControl_MouseClick); mapControl.MouseDown += new MouseEventHandler(mapControl_MouseDown); mapControl.MouseUp += new MouseEventHandler(mapControl_MouseUp); mapControl.MouseMove += new MouseEventHandler(mapControl_MouseMove); mapControl.OnMarkerClick += new MarkerClick(mapControl_OnMarkerClick); mapControl.OnMarkerEnter += new MarkerEnter(mapControl_OnMarkerEnter); mapControl.OnMarkerLeave += new MarkerLeave(mapControl_OnMarkerLeave); mapControl.Overlays.Add(objects); } void mapControl_MouseMove(object sender, MouseEventArgs e) { if (e.Button == System.Windows.Forms.MouseButtons.Left && isLeftButtonDown) { if (currentMarker != null) { PointLatLng point = mapControl.FromLocalToLatLng(e.X, e.Y); currentMarker.Position = point; currentMarker.ToolTipText = string.Format("{0},{1}", point.Lat, point.Lng); } } } void mapControl_MouseUp(object sender, MouseEventArgs e) { if (e.Button == System.Windows.Forms.MouseButtons.Left) { isLeftButtonDown = false; } } void mapControl_MouseDown(object sender, MouseEventArgs e) { if (e.Button == System.Windows.Forms.MouseButtons.Left) { isLeftButtonDown = true; } } void mapControl_OnMarkerLeave(GMapMarker item) { if (item is GMapMarkerImage) { currentMarker = null; GMapMarkerImage m = item as GMapMarkerImage; m.Pen.Dispose(); m.Pen = null; } } void mapControl_OnMarkerEnter(GMapMarker item) { if (item is GMapMarkerImage) { currentMarker = item as GMapMarkerImage; currentMarker.Pen = new Pen(Brushes.Red, 2); } } void mapControl_OnMarkerClick(GMapMarker item, MouseEventArgs e) { } void mapControl_MouseClick(object sender, MouseEventArgs e) { if(e.Button == System.Windows.Forms.MouseButtons.Right) { //objects.Markers.Clear(); PointLatLng point = mapControl.FromLocalToLatLng(e.X,e.Y); //GMapMarker marker = new GMarkerGoogle(point, GMarkerGoogleType.green); Bitmap bitmap = Bitmap.FromFile("F:\\Projects\\GMapDemo\\GMapDemo\\Image\\A.png") as Bitmap; //GMapMarker marker = new GMarkerGoogle(point, bitmap); GMapMarker marker = new GMapMarkerImage(point, bitmap); marker.ToolTipMode = MarkerTooltipMode.OnMouseOver; marker.ToolTipText = string.Format("{0},{1}", point.Lat, point.Lng); objects.Markers.Add(marker); } } void mapControl_OnMapZoomChanged() { } private void buttonBeginBlink_Click(object sender, EventArgs e) { blinkTimer.Interval = 1000; blinkTimer.Tick += new EventHandler(blinkTimer_Tick); blinkTimer.Start(); } void blinkTimer_Tick(object sender, EventArgs e) { foreach (GMapMarker m in objects.Markers) { if (m is GMapMarkerImage) { GMapMarkerImage marker = m as GMapMarkerImage; if (marker.OutPen == null) marker.OutPen = new Pen(Brushes.Red, 2); else { marker.OutPen.Dispose(); marker.OutPen = null; } } } mapControl.Refresh(); } private void buttonStopBlink_Click(object sender, EventArgs e) { blinkTimer.Stop(); foreach (GMapMarker m in objects.Markers) { if (m is GMapMarkerImage) { GMapMarkerImage marker = m as GMapMarkerImage; marker.OutPen.Dispose(); marker.OutPen = null; } } mapControl.Refresh(); } } } 作者: 阿凡卢 出处: http://www.cnblogs.com/luxiaoxun/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。http://www.cnblogs.com/luxiaoxun/p/3475355.html

资源下载

更多资源
Mario

Mario

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

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

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等操作系统。

用户登录
用户注册