如何实时更新Ruby GTK window标签并与其他线程通信
How to update Ruby GTK window label in real time and communicate with other threads
我正在构建一个 Ruby 应用程序,其中包含负责程序逻辑的代码和负责 GUI 的代码。代码的两部分在 classes 和 运行 中拆分在不同的线程中。
Ruby Gtk 库的文档非常少。 我想知道如何实时更新特定的 Gtk 元素(例如,标签中的文本位于 window 中)。我想每秒更新一个特定的元素。
我也想知道线程如何交换数据。我试过使用队列库。当我使用它时,我 运行 在控制台中出现错误:
undefined local variable or method `queue' for #<TimerWindow:0xa36d634 ptr=0xb4201178>
程序代码:
require_relative 'notifications'
require_relative 'settings_reader'
require 'gtk3'
require "thread"
q = Queue.new
class TimerWindow < Gtk::Window
def initialize
@label = ""
super
init_ui
end
def init_ui
fixed = Gtk::Fixed.new
add fixed
button = Gtk::Button.new :label => "Quit"
button.set_size_request 80, 35
button.signal_connect "clicked" do
@label.set_text q.pop
end
fixed.put button, 50, 50
set_title "Tomatono"
signal_connect "destroy" do
Gtk.main_quit
end
set_border_width 10
@label = Gtk::Label.new "HEY"
fixed.put @label, 20, 20
set_default_size 250, 200
set_window_position :center
show_all
end
end
class Timer
def initialize
# Current time in seconds
@time = 0
settings = Settings_Reader.new
@work_time = Integer(settings.work_time) * 60
@break_time = Integer(settings.break_time) * 60
@work_text = settings.work_text
@return_text = settings.return_text
@break_text = settings.break_text
@work_notif_header = settings.work_notif_header
@break_notif_header = settings.break_notif_header
@status_notif_header = settings.status_notif_header
@work_status = settings.work_status
@break_status = settings.break_status
end
def launch
while true
work_time()
break_time()
end
end
def work_time()
puts @work_text
notification = Notif.new(@work_notif_header, @work_text)
notification.post
@time = 0
sleep(1)
while @time < @work_time
@time += 1
puts "#{min_remaining()} minutes remaining" if (@time % 60) == 0
if (@time % 60) == 0
notification = Notif.new(@work_notif_header, "#{@work_status} #{@time / 60} minutes.")
notification.post
end
q << @time
sleep(1)
end
end
def break_time
puts @break_text
@time = 0
sleep(1)
while @time < @break_time
@time += 1
puts "#{min_remaining()} minutes remaining" if (@time % 60) == 0
notification = Notif.new(@break_notif_header, "#{@break_status} #{@time / 60} minutes.")
notification.post
q << @time
sleep(1)
end
end
def reset
end
def stop_time
end
def min_remaining()
(1500 - @time) / 60
end
end
app = Thread.new {
timer = Timer.new
timer.launch
}
gui = Thread.new {
Gtk.init
window = TimerWindow.new
#window.update
Gtk.main
}
app.join
gui.join
每当我按下 "Quit" 按钮时,我希望标签文本更改为 q 变量中设置的值,在定时器 class 中设置(在 while 循环中)。但是它抛出一个变量不存在的错误。它不应该是全球性的吗?
否 是局部变量:
myglobal = "toto"
class Myclass
def initialize
@myvar = myglobal
end
def print
puts @myvar
end
end
an_instance = Myclass.new
an_instance.print
抛出此错误:
global_and_class.rb:5:in `initialize': undefined local variable or method `myglobal' for #<Myclass:0x00000000a74ce8> (NameError)
但如果您将 myglobal 指定为全局变量,它会起作用:
$myglobal = "toto"
class Myclass
def initialize
@myvar = $myglobal
end
def print
puts @myvar
end
end
an_instance = Myclass.new
an_instance.print
但是你应该小心使用全局变量。为什么不使用 Queue 实例作为初始化方法的参数?
** 编辑 **
首先,这是一个仅使用局部变量的简单示例:
#!/usr/bin/env ruby
require "gtk3"
label = Gtk::Label.new("test")
othert = Thread.new {
loop {
puts 'thread running';
label.text = Time.now.to_s; sleep 1 }
}
maint = Thread.new {
win = Gtk::Window.new
win.set_default_size 100, 30
win.add(label)
win.show_all
win.signal_connect("destroy") {othert.kill;Gtk.main_quit}
Gtk.main
}
maint.join
othert.join
或许你应该从这里开始,看看如何造就你类。
编辑 2
class TimerWindow < Gtk::Window
def initialize(label)
super()
add(label)
end
end
alabel = Gtk::Label.enw("test")
othert = Thread.new {
loop {
puts 'thread running';
label.text = Time.now.to_s; sleep 1 }
}
maint = Thread.new {
win = TimerWindow.new(alabel)
win.set_default_size 100, 30
win.show_all
win.signal_connect("destroy") {othert.kill;Gtk.main_quit}
Gtk.main
}
maint.join
othert.join
我正在构建一个 Ruby 应用程序,其中包含负责程序逻辑的代码和负责 GUI 的代码。代码的两部分在 classes 和 运行 中拆分在不同的线程中。
Ruby Gtk 库的文档非常少。 我想知道如何实时更新特定的 Gtk 元素(例如,标签中的文本位于 window 中)。我想每秒更新一个特定的元素。
我也想知道线程如何交换数据。我试过使用队列库。当我使用它时,我 运行 在控制台中出现错误:
undefined local variable or method `queue' for #<TimerWindow:0xa36d634 ptr=0xb4201178>
程序代码:
require_relative 'notifications'
require_relative 'settings_reader'
require 'gtk3'
require "thread"
q = Queue.new
class TimerWindow < Gtk::Window
def initialize
@label = ""
super
init_ui
end
def init_ui
fixed = Gtk::Fixed.new
add fixed
button = Gtk::Button.new :label => "Quit"
button.set_size_request 80, 35
button.signal_connect "clicked" do
@label.set_text q.pop
end
fixed.put button, 50, 50
set_title "Tomatono"
signal_connect "destroy" do
Gtk.main_quit
end
set_border_width 10
@label = Gtk::Label.new "HEY"
fixed.put @label, 20, 20
set_default_size 250, 200
set_window_position :center
show_all
end
end
class Timer
def initialize
# Current time in seconds
@time = 0
settings = Settings_Reader.new
@work_time = Integer(settings.work_time) * 60
@break_time = Integer(settings.break_time) * 60
@work_text = settings.work_text
@return_text = settings.return_text
@break_text = settings.break_text
@work_notif_header = settings.work_notif_header
@break_notif_header = settings.break_notif_header
@status_notif_header = settings.status_notif_header
@work_status = settings.work_status
@break_status = settings.break_status
end
def launch
while true
work_time()
break_time()
end
end
def work_time()
puts @work_text
notification = Notif.new(@work_notif_header, @work_text)
notification.post
@time = 0
sleep(1)
while @time < @work_time
@time += 1
puts "#{min_remaining()} minutes remaining" if (@time % 60) == 0
if (@time % 60) == 0
notification = Notif.new(@work_notif_header, "#{@work_status} #{@time / 60} minutes.")
notification.post
end
q << @time
sleep(1)
end
end
def break_time
puts @break_text
@time = 0
sleep(1)
while @time < @break_time
@time += 1
puts "#{min_remaining()} minutes remaining" if (@time % 60) == 0
notification = Notif.new(@break_notif_header, "#{@break_status} #{@time / 60} minutes.")
notification.post
q << @time
sleep(1)
end
end
def reset
end
def stop_time
end
def min_remaining()
(1500 - @time) / 60
end
end
app = Thread.new {
timer = Timer.new
timer.launch
}
gui = Thread.new {
Gtk.init
window = TimerWindow.new
#window.update
Gtk.main
}
app.join
gui.join
每当我按下 "Quit" 按钮时,我希望标签文本更改为 q 变量中设置的值,在定时器 class 中设置(在 while 循环中)。但是它抛出一个变量不存在的错误。它不应该是全球性的吗?
否 是局部变量:
myglobal = "toto"
class Myclass
def initialize
@myvar = myglobal
end
def print
puts @myvar
end
end
an_instance = Myclass.new
an_instance.print
抛出此错误:
global_and_class.rb:5:in `initialize': undefined local variable or method `myglobal' for #<Myclass:0x00000000a74ce8> (NameError)
但如果您将 myglobal 指定为全局变量,它会起作用:
$myglobal = "toto"
class Myclass
def initialize
@myvar = $myglobal
end
def print
puts @myvar
end
end
an_instance = Myclass.new
an_instance.print
但是你应该小心使用全局变量。为什么不使用 Queue 实例作为初始化方法的参数?
** 编辑 **
首先,这是一个仅使用局部变量的简单示例:
#!/usr/bin/env ruby
require "gtk3"
label = Gtk::Label.new("test")
othert = Thread.new {
loop {
puts 'thread running';
label.text = Time.now.to_s; sleep 1 }
}
maint = Thread.new {
win = Gtk::Window.new
win.set_default_size 100, 30
win.add(label)
win.show_all
win.signal_connect("destroy") {othert.kill;Gtk.main_quit}
Gtk.main
}
maint.join
othert.join
或许你应该从这里开始,看看如何造就你类。
编辑 2
class TimerWindow < Gtk::Window
def initialize(label)
super()
add(label)
end
end
alabel = Gtk::Label.enw("test")
othert = Thread.new {
loop {
puts 'thread running';
label.text = Time.now.to_s; sleep 1 }
}
maint = Thread.new {
win = TimerWindow.new(alabel)
win.set_default_size 100, 30
win.show_all
win.signal_connect("destroy") {othert.kill;Gtk.main_quit}
Gtk.main
}
maint.join
othert.join