可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am using the powerful Sublime Text 3 editor on MacOSX to run python codes. I want to display a progress bar of a for loop, and the following command:
sys.stdout.write('\rProgress : %03.2f %%' % (100*float(i)/(N)))
sys.flush()
does not clear the previously printed line in the output window as expected (\r
) but produces N
lines:
Progress : 0.25 %
Progress : 0.50 %
Progress : 0.75 %
Progress : 1.00 %
Progress : 1.25 %
Progress : 1.50 %
Progress : 1.75 %
Progress : 2.00 %
Progress : 2.25 %
Progress : 2.50 %
...
Which is not really nice to read – I conclude that the output window might be read-only.
Does anyone have suggestions to improve the use of progress bars in Sublime Text?
回答1:
Taking a look at sublime.py
we see that the flush
method actually does nothing:
class _LogWriter:
def flush(self):
pass
def write(self, s):
sublime_api.log_message(s)
sys.stdout = _LogWriter()
sys.stderr = _LogWriter()
However I would not recommend to use the console for user outputs anyway. Usually you use output panels/views or status messages.
Status messages are easier to use, but less powerful. sergioFC demonstrated this in his answer.
This demonstrates how to use an output panel. It is very flexible, but you must write your own text command to insert the text. This is necessary, because you need an edit object to change the content of the view.
import sublime
import sublime_plugin
class MyInsertProgressBarCommand(sublime_plugin.TextCommand):
def run(self, edit, value):
view = self.view
width, _ = view.viewport_extent()
em_width = view.em_width()
# the number of columns are the width divided by the width of a char
# subtract two to add a little border
columns = int(width / em_width) - 2
# subtract two, because we surround it with [ and ]
bar_length = columns - 2
# calculate the size of the filled and the remaining part
filled_length = int(bar_length * value / 100)
remaining_length = bar_length - filled_length
# assemble the string for the progress bar
text = "[{0}{1}]\n".format("=" * filled_length, "." * remaining_length)
# add the text for the percentages
if value >= 100:
percentage_text = "finished!"
else:
percentage_text = "{:3.2f} %".format(value)
text += " " * (columns - len(percentage_text)) + percentage_text
# replace the content of the view
view.replace(edit, sublime.Region(0, view.size()), text)
# reset sels
view.sel().clear()
view.sel().add(sublime.Region(0, 0))
class ProgressBarCommand(sublime_plugin.WindowCommand):
def run(self):
self.window.create_output_panel("progess_bar")
self.window.run_command("show_panel", {"panel": "output.progess_bar"})
def test_progress_bar():
import random
test_progress_bar.value += 2 * random.random()
if test_progress_bar.value >= 100:
self.finish_progress()
return
self.show_progress(test_progress_bar.value)
sublime.set_timeout(test_progress_bar, 100)
test_progress_bar.value = 0
sublime.set_timeout_async(test_progress_bar, 1)
def show_progress(self, progess):
view = self.window.find_output_panel("progess_bar")
view.run_command("my_insert_progress_bar", {"value": progess})
def finish_progress(self):
self.show_progress(100)
sublime.set_timeout(self._destroy, 5000)
def _destroy(self):
self.window.destroy_output_panel("progess_bar")
The output:
![](https://www.manongdao.com/static/images/pcload.jpg)
回答2:
As another alternative solution you can use status bar. When you you set the status bar message the previous text is cleared. Package control also uses status bar while installing packages.
Example:
![](https://www.manongdao.com/static/images/pcload.jpg)
import sublime, sublime_plugin
import time
class ExampleCommand(sublime_plugin.WindowCommand):
def run(self, args):
sublime.set_timeout_async(self.test,1)
def test(self):
i=80
while i <= 100:
sublime.status_message('%03.2f %%' % i)
time.sleep(0.15)
i+=0.25
sublime.status_message('100% Stackoverflow!')
回答3:
You can create a visual progress bar using:
- the mdpopups library
sublime.set_timeout
or sublime.set_timeout_async
( see: Sublime Module )
Demo:
![](https://www.manongdao.com/static/images/pcload.jpg)
Code:
@ GitHub
( run the plugin by typing Progress Bar Demo
@ the Command Palette )
Notes:
There is a css file that controls the style of mdpopups
.
For some reason, the color
property isn't having any effect.
Also, mdpopups.show_popup
's location
parameter takes -1
for the popup to be set at the caret position.
Otherwise, I'm not sure how location
affects the popup, since it only takes a single integer value.
I've inquired about these issues at the following thread:
[Proof Of Concept] Visual Progress Bar
回答4:
What you might be looking for is a way to keep the output from consuming multiple lines. You can print \b
(the backspace character) as many times as there were previously printed characters. I wrote this as an example:
(Python 2.7.6)
from __future__ import print_function
import time, sys
for i in range(1, 6):
print(i, end='')
sys.stdout.flush()
time.sleep(0.5)
print('\b', end='')
Try running that and you can adapt it to your needs.
回答5:
You can use progressbar library. located here : https://pypi.python.org/pypi/progressbar/2.3-dev
Also you can install it from easy_install just type : easy_install progressbar
Example to use :
if you want simple progressbar with out information about function :
from progressbar import *
from time import sleep
progress = ProgressBar()
for i in progress(range(80)):
sleep(0.01)
else if you want progressbar with information about function :
from progressbar import *
from time import sleep
widgets = ['Something: ', Percentage(), ' ', Bar(marker=RotatingMarker()),
' ', ETA(), ' ', FileTransferSpeed()]
pbar = ProgressBar(widgets=widgets, maxval=10000000).start()
for i in range(1000000):
# do something
pbar.update(10*i+1)
sleep(0.000001)
pbar.finish()
回答6:
Unfortunately, this is not possible in Sublime's output panel. The panel is not a true console or terminal, and among other differences does not interpret escape sequences such as \r
and \b
(\n
is interpreted correctly, however). If you want to see how exactly it works, install PackageResourceViewer
, then open Packages/Default/exec.py
.
In order to get this to work, you'll need to create a new build system to run it in Terminal. Due to the vagaries of OS X, you'll need to create two files. The first is a shell script:
#!/bin/sh
osascript -e '
on run parameters
tell application "Terminal"
activate
do script with command "/path/to/python " & parameters
end tell
end run
' $@
Change /path/to
with your actual path to python
(or python3
). Save it wherever you want as PythonTerminal.sh
. Next, select Tools -> Build System -> New Build System
and paste in the following:
{
"cmd": ["/bin/sh /path/to/Python3Terminal.sh \"$file\""],
"file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
"selector": "source.python",
"shell": true
}
Again, change /path/to
to the actual path to PythonTerminal.sh
. Save the file as Packages/User/PythonTerminal.sublime-build
(it should automatically open the correct directory when saving).
Finally, select Tools -> Build System -> PythonTerminal
, switch to your Python file, and build with ⌘B. A new Terminal window will open and your progress bar should run.