How to use progressbar indeterminate in ruby/tk? - ruby

I cant figure out how the progressbar in ruby/tk works in indeterminate mode.
I can get the progressbar showing but it will not move.
an example if I just use this line in my code
progressBar.start
If I only have that line the progressbar will be showing and moving as it should.
But if i add line of code under it it will not execute. I had the impression that the .start method of progressbar starts it and the method stop stops it and in between you have the code that should be executed and the progressbar show until it sees the stop.
But if i do this
progressBar.start
# some code (a loop that takes a long while to execute)
progressBar.stop
the progressbar is not beeing shown until the code in between is finished? I thought that was why you wanted the progressbar?
What am I not understanding here.
Thx for you help but why is not this working. Its just a stupid test. But i am doing somthing similar in the real program. If I write this code the progressbar will not run as it should but instead after the Devil img loop is done?
Dir.chdir("c:/temp")
bilder = Dir.glob("*.jpg")+
bilder = Dir.glob("*.png")+
bilder = Dir.glob("*.gif")
puts bilder
root = TkRoot.new { title 'Progressbar Demo' }
content = Tk::Frame.new(root) {}.grid(:sticky =>'new')
progress = Tk::Tile::Progressbar.new(content:mode=>'indeterminate':orient=>:horizontal)
progress.pack
Thread.new do
progress.start
i=0
while i < bilder.length
Devil.with_image(bilder[i]) do |img|
img.thumbnail2(150)
img.save("thumbnail_"+ bilder[i])
end
i=i+1
end
progress.stop
end
Tk.mainloop

It is a threading problem.
This code should work. Tested on Win7, Ruby 1.9.3
require 'tk'
root = TkRoot.new { title 'Progressbar Demo' }
progress = Tk::Tile::Progressbar.new(root, :mode=>'determinate', :orient=>:horizontal, :maximum=>100)
progress.pack
Thread.new do
99.times do |i|
progress.step(1) #or progress.value = i
puts i
sleep 0.1
end
end
Tk.mainloop
For your indeerminate version that is
require 'tk'
root = TkRoot.new { title 'Progressbar Demo' }
progress = Tk::Tile::Progressbar.new(root, :mode=>'indeterminate', :orient=>:horizontal)
progress.pack
Thread.new do
progress.start
99.times do |i|
puts i
sleep 0.1
end
progress.stop
end
Tk.mainloop
Here an example how to do it wiht green shoes
require 'green_shoes'
Shoes.app do
#p = progress
#animate = animate do |percent|
#animate.stop if percent > 99
puts percent
#p.fraction = percent.to_f / 100
end
end
EDIT: based on the added question here a reworked more rubylike version of your script
unfortionatly i had to comment out the Devil lines cause i can't get this gem to work (loaderror)
require 'tk'
# require 'devil'
bilder = Dir['c:/temp/*.{jpg,png,gif}']
root = TkRoot.new { title 'Progressbar Demo' }
progress = Tk::Tile::Progressbar.new(root, :mode=>'indeterminate', :orient=>'horizontal')
progress.pack
STDOUT.sync = true
Thread.new do
progress.start
bilder.each do |bild|
puts bild
sleep 0.5
# Devil.with_image(bild) do |img|
# img.thumbnail2(150)
# img.save("thumbnail_#{bild}")
# end
end
progress.stop
end
Tk.mainloop
LAST EDIT:
here a working example with mini_magick since devil doesn't work on any of my pc's and gives problem with TK
['mini_magick','tk','fileutils'].each(&method(:require))
bilder = Dir['c:/test/*.{jpg,png,gif}']
root = TkRoot.new { title 'Progressbar Demo' }
progress = Tk::Tile::Progressbar.new(root, :mode=>'indeterminate', :orient=>'horizontal')
progress.pack
STDOUT.sync = true
def generate file, out, type
image = MiniMagick::Image.open file
if type == :thumb
image.resize "92x92"
elsif type == :slide
image.resize "800x600"
end
image.write out
end
Thread.new do
progress.start
bilder.each do |bild|
puts bild
generate bild, bild+'.thumb.jpg', :thumb
end
progress.stop
progress.destroy
end
Tk.mainloop

Related

Use GTK3 progress bars in Ruby

This is my code:
require "gtk3"
builder_file = "#{File.expand_path(File.dirname(__FILE__))}/example.ui"
builder = Gtk::Builder.new(:file => builder_file)
window = builder.get_object("window")
window.signal_connect("destroy") { Gtk.main_quit }
progressbar=builder.get_object("progressbar1")
progressbar.set_fraction(0.5)
button = builder.get_object("button1")
button.signal_connect("clicked") {
for i in(0..4)
sleep(1)
puts "query " + (i+1).to_s + " done"
a=(i+1)/5.to_f
puts a
progressbar.set_fraction(a)
end
}
Gtk.main
sleep is just a placeholder for a web query that takes about 1 second. When I execute this code on my machine, the console output is fine, but the progress bar stays empty until it jumps to full after five seconds, which is not what I want. How can I make use of the progress bar?
The integration of the event loop of the GUI tool (Gtk, Tk, etc) and Ruby annoys beginners including me. I know two ways.
1.add thread
require 'gtk3'
win = Gtk::Window.new('Sample')
win.signal_connect('destroy') { Gtk.main_quit }
box = Gtk::Box.new(:vertical)
pb = Gtk::ProgressBar.new
pb.set_fraction(0.5)
b = Gtk::Button.new(label: 'Button')
b.signal_connect('clicked') do
Thread.new do
5.times do |i|
sleep 1
pb.fraction = (i + 1) / 5.0
end
end
end
win.add box
box.pack_start pb
box.pack_start b
win.show_all
Gtk.main
2.use GLib::Timeout
b.signal_connect('clicked') do
i = 0.0
GLib::Timeout.add(1000) do |a|
i += 0.2
pb.fraction = i
i < 1.0 # return false and stop when i >= 1.0
end
end

Ruby Mechanize Stops Working while in Each Do Loop

I am using a mechanize Ruby script to loop through about 1,000 records in a tab delimited file. Everything works as expected until i reach about 300 records.
Once I get to about 300 records, my script keeps calling rescue on every attempt and eventually stops working. I thought it was because I had not properly set max_history, but that doesn't seem to be making a difference.
Here is the error message that I start getting:
getaddrinfo: nodename nor servname provided, or not known
Any ideas on what I might be doing wrong here?
require 'mechanize'
result_counter = 0
used_file = File.open(ARGV[0])
total_rows = used_file.readlines.size
mechanize = Mechanize.new { |agent|
agent.open_timeout = 10
agent.read_timeout = 10
agent.max_history = 0
}
File.open(ARGV[0]).each do |line|
item = line.split("\t").map {|item| item.strip}
website = item[16]
name = item[11]
if website
begin
tries ||= 3
page = mechanize.get(website)
primary1 = page.link_with(text: 'text')
secondary1 = page.link_with(text: 'other_text')
contains_primary = true
contains_secondary = true
unless contains_primary || contains_secondary
1.times do |count|
result_counter+=1
STDERR.puts "Generate (#{result_counter}/#{total_rows}) #{name} - No"
end
end
for i in [primary1]
if i
page_to_visit = i.click
page_found = page_to_visit.uri
1.times do |count|
result_counter+=1
STDERR.puts "Generate (#{result_counter}/#{total_rows}) #{name}"
end
break
end
end
rescue Timeout::Error
STDERR.puts "Generate (#{result_counter}/#{total_rows}) #{name} - Timeout"
rescue => e
STDERR.puts e.message
STDERR.puts "Generate (#{result_counter}/#{total_rows}) #{name} - Rescue"
end
end
end
You get this error because you don't close the connection after you used it.
This should fix your problem:
mechanize = Mechanize.new { |agent|
agent.open_timeout = 10
agent.read_timeout = 10
agent.max_history = 0
agent.keep_alive = false
}

Signal timed ruby gtk image change without button_press_event, how to trigger looping

The line: pics.box.signal_connect("button_press_event"){pics.nuImage}, triggers nuImage and adds 1 to the picindex counter upon clicking, making the current image destroy, and next image show. I would like to make this automatic, like a slideshow without having to click. It needs to show a new image every x amount of seconds, using a sleep or something like GLib.timeout_add_seconds (), but I do not understand how to implement these options to continue looping without any user input. Thank you for your help, I am very new to ruby.
require 'gtk2'
class Pics
attr_accessor :pile, :picindex, :imgLoaded, :image, :box, :window, :time
def initialize
#window = Gtk::Window.new()
#window.signal_connect("destroy"){Gtk.main_quit}
pic1 = "1.jpg"
pic2 = "2.jpg"
pic3 = "3.jpg"
pic4 = "4.jpg"
#pile = [pic1, pic2, pic3, pic4]
#picindex = 0
self.getImage
#box = Gtk::EventBox.new.add(#image)
#time = true
end
def nuImage
#box.remove(#image)
#picindex = #picindex + 1
#picindex = 0 if #picindex == #pile.length
self.getImage
#box.add(#image)
#box.show
end
def getImage
#imgLoaded = #pile[#picindex]
img = Gdk::Pixbuf.new(#imgLoaded, 556, 900)
#image = Gtk::Image.new(img)
#image.show
end
end # class Pics
pics = Pics.new
pics.box.signal_connect("button_press_event"){pics.nuImage}
pics.window.set_default_size(556, 900)
pics.window.add(pics.box)
pics.window.show_all
Gtk.main
the following code is an implementation:
GLib::Timeout.add(1000) do
pics.nuImage if pics.time
true
end
pics.window.signal_connect("key_press_event") do |_window, event|
case event.keyval
when Gdk::Keyval::GDK_KEY_space
pics.time = !pics.time
end
end
more details: http://ruby-gnome2.sourceforge.jp/hiki.cgi?GLib%3A%3ATimeout
related: Ruby GTK Pixbuf timed image change

Ruby GTK Pixbuf timed image change

I am creating an image slideshow in ruby, using gtk pixbuf to load images. I am very new to ruby & GTK, this may be an stupid question.
Currently image changes are linked to the GUI button_press_event, I would like them to change /refresh automatically based on a set time, like a slideshow or animation. I saw the gtk animation using a gif method, but I would like to use individual jpeg files inline sequence, so that I can set the time to show a slide. Once the loop has gone through all the images, the GUI should display buttons for replay or quit. ( I haven't used #time yet, it is just there for possibilities ) Thanks for any suggestions;
require 'gtk2'
class Pics
attr_accessor :pile, :picindex, :imgLoaded, :image, :box, :window, :time
def initialize
#window = Gtk::Window.new()
#window.signal_connect("destroy"){Gtk.main_quit}
pic1 = "1.jpg"
pic2 = "2.jpg"
pic3 = "3.jpg"
pic4 = "4.jpg"
#pile = [pic1, pic2, pic3, pic4]
#picindex = 0
self.getImage
#box = Gtk::EventBox.new.add(#image)
#time = true
end
def nuImage
#box.remove(#image)
#picindex = #picindex + 1
#picindex = 0 if #picindex == #pile.length
self.getImage
#box.add(#image)
#box.show
end
def getImage
#imgLoaded = #pile[#picindex]
img = Gdk::Pixbuf.new(#imgLoaded, 556, 900)
#image = Gtk::Image.new(img)
#image.show
end
end # class Pics
pics = Pics.new
pics.box.signal_connect("button_press_event"){pics.nuImage}
pics.window.set_default_size(556, 900)
pics.window.add(pics.box)
pics.window.show_all
Gtk.main
use GLib.timeout_add () or GLib.timeout_add_seconds (). Return False if you don't want to use it anymore.read GLib documentation, Section: Main Event Loop
This is a solution:
def start_button__clicked(but)
#thread = Thread.new {
loop do
next_button__clicked
sleep(2)
end
end
def stop_button__clicked(but)
#thread.kill
end
This is how I would do it in visual ruby. Its basically the same.
You'd just have a form with a button named "start_button" and "stop_button" etc.
the following code is an implementation:
GLib::Timeout.add(1000) do
pics.nuImage if pics.time
true
end
pics.window.signal_connect("key_press_event") do |_window, event|
case event.keyval
when Gdk::Keyval::GDK_KEY_space
pics.time = !pics.time
end
end
more details:
http://ruby-gnome2.sourceforge.jp/hiki.cgi?GLib%3A%3ATimeout

ruby Tk app running in while loop displays twice and then stops responding

I'm pretty new to ruby and am trying to implement a Tk application that will display a window prompting for input at a certain interval. In between the interval I want the window to not display in any taskbars, etc. and so I've implemented the following code that seems to work perfectly the first time through, but after the window displays the second time and I enter text in the TkEntry and click the TkButton the window is dismissed and never returns. I've tried putting in some "puts" calls at key locations to see what is happening and it seems that it never even makes it past the call to "displayUi".
*EDIT:
I'm running ruby 1.9.3p385 (2013-02-06) [i386-mingw32] on a Windows 7 system (in case that makes any difference)
Any help (even if it's providing a different mechanism to accomplish the same goal) would be appreciated, but please keep in mind that I'm a ruby noobie. Thanks!
require "tk"
class Sample
attr_accessor :root, :active
#active = false
def initialize
# init
end
def entry (task)
# do some work here
#active = false
end
def displayUi ()
#active = true
if (#root.nil?)
#root = TkRoot.new { title "Sample App" }
else
# already running just restart
Tk.restart
end
TkLabel.new(#root) {
text 'Sample Text'
pack { padx 15; pady 15; side 'left' }
}
statusInput = TkEntry.new(#root) {
pack('side'=>'left', 'padx'=>10, 'pady'=>10)
}
statusInput.focus
response = TkVariable.new
statusInput.textvariable = response
TkButton.new(#root, :text => "Ok", :command => proc { entry(response.value); #root.destroy }) {
pack('side'=>'left', 'padx'=>10, 'pady'=>10)
}
Tk.mainloop
end
end
i=0
st = Sample.new
while (true)
if (!st.active)
st.displayUi()
end
sleep(1)
end

Resources