如何在Shoes中使用进度条?

时间:2023-01-16 12:00:46

Ok, so I'm not real sure about lots of things in Shoes, but my trial and error approach has failed me so far on this one.

好的,所以我不太确定鞋子里有很多东西,但到目前为止,我的试错方法在这个方面都没有让我失望。

I've got a class that does some sort of computation that takes a while, and I want to throw up a progress bar for the user to look at while it finishes. My computationally intensive method yields its percent complete if passed a block:

我有一个类需要一段时间进行某种计算,我希望在完成时让用户查看进度条。如果传递一个块,我的计算密集型方法会产生完整百分比:

class MathyStuff

  def initialize()
  end

  ## Some expensive, time consuming method which yields it's percent complete
  def expensiveMethod(&block)
    0.upto(100) do |i|
      0.upto(100000) do |j|
        k = j;
      end

      yield i.to_f/100;
    end
  end

end

Here's what I'd like to say in Shoes:

这是我想在鞋子里说的话:

require 'MathyStuff.rb'

Shoes.app do

  @myMathyStuff = MathyStuff.new();

  button("Do expensive mathy thing...") do
    window() do
      @progress = progress();
      @myMathyStuff.expensiveMethod() {|percent| @progress.fraction = percent;}
    end
  end

end

But it doesn't seem to work. I've tried with/without the window call, I've tried animate() in various ways, I even tried calling Thread.new and passing it the window block, having them converse via Shoes.APPS()[0].get/setPercent methods; nothing seems to work properly.

但它似乎没有用。我已尝试使用/不使用窗口调用,我已尝试以各种方式使用animate(),我甚至尝试调用Thread.new并将其传递给窗口块,让它们通过Shoes.APPS()[0]进行交换。 / setPercent方法;似乎没有什么工作正常。

Maybe I'm not using the progress bar the way it's meant to be used. Then again, what else would a progress bar be for? ;-)

也许我没有按照它的使用方式使用进度条。那么,进步条还有什么用呢? ;-)

2 个解决方案

#1


First of all, sharing data between two windows in Shoes is a royal pain. I don't recommend it. Instead, hide the contents of the first window and bring up the progress bar in its place.

首先,在Shoes中的两个窗口之间共享数据是一种巨大的痛苦。我不推荐它。而是隐藏第一个窗口的内容并在其位置调出进度条。

Second, we'll extend MathyStuff to switch it from processing a block to providing a percent attribute, so we can access it from an animation thread:

其次,我们将扩展MathyStuff以将其从处理块切换到提供百分比属性,因此我们可以从动画线程访问它:

class MathyStuff
  attr_accessor :percent

  def expensiveMethodWrapper
    @percent = 0.0
    expensiveMethod {|x| @percent = x}
  end
end

Shoes.app do

  @myMathyStuff = MathyStuff.new();
  @window_slot = stack do
    button("Do expensive mathy thing...") do
      @window_slot.toggle
      @progress_slot = flow do
        @progress = progress :width => 1.0
      end
    end
    Thread.new do
        @myMathyStuff.expensiveMethodWrapper
    end
    @animate = animate do
      @progress.fraction = @myMathyStuff.percent
      if @myMathyStuff.percent == 1.0
        @progress_slot.remove
        @window_slot.toggle
        @animate.stop
      end
    end
  end
end

#2


As I understand it, things like the progress bar need to be redrawn to screen after being fed a percentage value, this is what you'd use animate for in this case.

据我所知,进度条之类的东西需要在输入百分比值后重新绘制到屏幕上,这就是你在这种情况下使用动画的方法。

If you just want to do what you've stated in your question, then this approach - although not very flexible - does work for your example. But because it separates your progress logic from your actual method, you can only change the percentage values before and after you run those methods. So, since you're just running an iteration 100 times, then you can do it effectively this way.

如果你只想做你在问题中所说的话,那么这种方法 - 虽然不是很灵活 - 确实适用于你的例子。但是因为它将您的进度逻辑与实际方法分开,所以您只能在运行这些方法之前和之后更改百分比值。所以,既然你只是运行了100次迭代,那么你可以通过这种方式有效地完成它。

class Mathy
  def foo
    100000.times do |bar|
      foo = bar
    end
  end
end

Shoes.app do
  @mathy = Mathy.new
  button("Run") do
    @p = progress
    animate do |percent|
      break if percent > 100
      @mathy.foo
      @p.fraction = percent.to_f / 100
    end
  end
end

If your method is doing more than just repeating the same iteration, then yes, you'd want to yield its progress frequently from within the method. Then, in order to return that progress from the method while it's running, you could put it in a separate thread as Pesto suggested, and just poll it for the progress in your animate block. Using an attr_accessor for returning the percentage is also a good idea. Hope that helps.

如果您的方法不仅仅是重复相同的迭代,那么是的,您希望经常从方法中获得进度。然后,为了在方法运行时从方法返回该进度,您可以将其放在Pesto建议的单独线程中,并且只是轮询它以获取动画块中的进度。使用attr_accessor返回百分比也是一个好主意。希望有所帮助。

#1


First of all, sharing data between two windows in Shoes is a royal pain. I don't recommend it. Instead, hide the contents of the first window and bring up the progress bar in its place.

首先,在Shoes中的两个窗口之间共享数据是一种巨大的痛苦。我不推荐它。而是隐藏第一个窗口的内容并在其位置调出进度条。

Second, we'll extend MathyStuff to switch it from processing a block to providing a percent attribute, so we can access it from an animation thread:

其次,我们将扩展MathyStuff以将其从处理块切换到提供百分比属性,因此我们可以从动画线程访问它:

class MathyStuff
  attr_accessor :percent

  def expensiveMethodWrapper
    @percent = 0.0
    expensiveMethod {|x| @percent = x}
  end
end

Shoes.app do

  @myMathyStuff = MathyStuff.new();
  @window_slot = stack do
    button("Do expensive mathy thing...") do
      @window_slot.toggle
      @progress_slot = flow do
        @progress = progress :width => 1.0
      end
    end
    Thread.new do
        @myMathyStuff.expensiveMethodWrapper
    end
    @animate = animate do
      @progress.fraction = @myMathyStuff.percent
      if @myMathyStuff.percent == 1.0
        @progress_slot.remove
        @window_slot.toggle
        @animate.stop
      end
    end
  end
end

#2


As I understand it, things like the progress bar need to be redrawn to screen after being fed a percentage value, this is what you'd use animate for in this case.

据我所知,进度条之类的东西需要在输入百分比值后重新绘制到屏幕上,这就是你在这种情况下使用动画的方法。

If you just want to do what you've stated in your question, then this approach - although not very flexible - does work for your example. But because it separates your progress logic from your actual method, you can only change the percentage values before and after you run those methods. So, since you're just running an iteration 100 times, then you can do it effectively this way.

如果你只想做你在问题中所说的话,那么这种方法 - 虽然不是很灵活 - 确实适用于你的例子。但是因为它将您的进度逻辑与实际方法分开,所以您只能在运行这些方法之前和之后更改百分比值。所以,既然你只是运行了100次迭代,那么你可以通过这种方式有效地完成它。

class Mathy
  def foo
    100000.times do |bar|
      foo = bar
    end
  end
end

Shoes.app do
  @mathy = Mathy.new
  button("Run") do
    @p = progress
    animate do |percent|
      break if percent > 100
      @mathy.foo
      @p.fraction = percent.to_f / 100
    end
  end
end

If your method is doing more than just repeating the same iteration, then yes, you'd want to yield its progress frequently from within the method. Then, in order to return that progress from the method while it's running, you could put it in a separate thread as Pesto suggested, and just poll it for the progress in your animate block. Using an attr_accessor for returning the percentage is also a good idea. Hope that helps.

如果您的方法不仅仅是重复相同的迭代,那么是的,您希望经常从方法中获得进度。然后,为了在方法运行时从方法返回该进度,您可以将其放在Pesto建议的单独线程中,并且只是轮询它以获取动画块中的进度。使用attr_accessor返回百分比也是一个好主意。希望有所帮助。