Ruby Forum wxRuby > Problem with runtime error/segfault

Posted by Daniel Washburn (anomaly)
on 14.04.2008 04:32
Set all the alarms to something, it doesn't matter what except sometime
in the future and out of the way except for #1. Set the first alarm on,
to maybe 2 minutes from the time you run the program. Every time I run
it I get a segfault or a runtime error. What's wrong?

# Only works if turned on before it goes off on the the day that it will

$statusChoice = ["On", "Off"]
$hourChoice = ["00", "01", "02", "03", "04", "05", "06", "07", "08",
"09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20",
"21", "22", "23"]
$minChoice = ["00", "15", "30", "45"]
$secChoice = ["00", "15", "30", "45"]
require "Wx"
include Wx
require 'on-off.rb'
require 'Sets1.rb'

class SetsFrame < Frame
  def initialize()
    super(nil, -1, 'Settings')

    choices = ['Alarm # 1', 'Alarm # 2', 'Alarm # 3', 'Alarm # 4']

    @setsPanel = Panel.new(self)
    $whichAlarm = ComboBox.new(@setsPanel, -1, 'Alarm # 1',
DEFAULT_POSITION, DEFAULT_SIZE, choices,   CB_READONLY)
    @editButton = Button.new(@setsPanel, -1, 'Edit')
    evt_button(@editButton.get_id()) {|event|editButtonClick(event)}
    @setsPanelSizer = BoxSizer.new(VERTICAL)
    @setsPanel.set_sizer(@setsPanelSizer)
    @setsPanel.sizer.add($whichAlarm, 0, GROW|ALL, 2)
    @setsPanel.sizer.add(@editButton, 0, GROW|ALL, 2)
    show()
  end

  def editButtonClick(event)
    $whichAlarmVal = $whichAlarm.get_value()
    if $whichAlarmVal == 'Alarm # 1'
      require 'Sets1.rb'
    elsif $whichAlarmVal == 'Alarm # 2'
      require 'Sets2.rb'
    elsif $whichAlarmVal == 'Alarm # 3'
      require 'Sets3.rb'
    elsif $whichAlarmVal == 'Alarm # 4'
      require 'Sets4.rb'
    else
      # Nothings
    end

    EditFrame.new
  end
end

class EditFrame < Frame
  def initialize()
    super(nil, -1, 'Edit')

    @aPanel = Panel.new(self)
    @someText = StaticText.new(@aPanel, -1, "Edit", DEFAULT_POSITION,
DEFAULT_SIZE, ALIGN_CENTER)
    @comboStatus = ComboBox.new(@aPanel, -1, $statusDef,
DEFAULT_POSITION, DEFAULT_SIZE, $statusChoice, CB_READONLY)
    @hourText = StaticText.new(@aPanel, -1, "Hours")
    @comboHour = ComboBox.new(@aPanel, -1, $hourDef, DEFAULT_POSITION,
DEFAULT_SIZE, $hourChoice, CB_DROPDOWN)
    @minText = StaticText.new(@aPanel, -1, "Minutes")
    @comboMin = ComboBox.new(@aPanel, -1, $minDef, DEFAULT_POSITION,
DEFAULT_SIZE, $minChoice, CB_DROPDOWN)
    @secText = StaticText.new(@aPanel, -1, "Seconds")
    @comboSec = ComboBox.new(@aPanel, -1, $secDef, DEFAULT_POSITION,
DEFAULT_SIZE, $secChoice, CB_DROPDOWN)
    @textAlarm = StaticText.new(@aPanel, -1, "Alarm Text")
    @alarmText = TextCtrl.new(@aPanel, -1, $textDef, DEFAULT_POSITION,
DEFAULT_SIZE, TE_MULTILINE)
    @dayText = StaticText.new(@aPanel, -1, "Days")
    @checkSun = CheckBox.new(@aPanel, -1, "Sunday")
    @checkMon = CheckBox.new(@aPanel, -1, "Monday")
    @checkTue = CheckBox.new(@aPanel, -1, "Tuesday")
    @checkWed = CheckBox.new(@aPanel, -1, "Wednesday")
    @checkThu = CheckBox.new(@aPanel, -1, "Thursday")
    @checkFri = CheckBox.new(@aPanel, -1, "Friday")
    @checkSat = CheckBox.new(@aPanel, -1, "Saturday")
    @saveButton = Button.new(@aPanel, -1, 'Save')
    @defButton = Button.new(@aPanel, -1, 'Return to Defaults')
    evt_button(@saveButton.get_id()) {|event|saveButtonClick(event)}
    evt_button(@defButton.get_id()) {|event|defButtonClick(event)}
    @aPanelSizer = BoxSizer.new(VERTICAL)
    @aPanel.set_sizer(@aPanelSizer)
    @aPanel.sizer.add(@someText, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@comboStatus, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@hourText, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@comboHour, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@minText, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@comboMin, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@secText, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@comboSec, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@textAlarm, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@alarmText, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@dayText, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@checkSun, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@checkMon, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@checkTue, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@checkWed, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@checkThu, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@checkFri, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@checkSat, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@saveButton, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@defButton, 0, GROW|ALL, 2)
    @checkSun.set_value($sun)
    @checkMon.set_value($mon)
    @checkTue.set_value($tue)
    @checkWed.set_value($wed)
    @checkThu.set_value($thu)
    @checkFri.set_value($fri)
    @checkSat.set_value($sat)
    show()
  end

  def sets1
    File.open('Sets1.rb', 'w') do |f|
      f.puts "$statusDef = \"#{$comboStatusVal}\"
$hourDef = \"#{$comboHourVal}\"
$minDef = \"#{$comboMinVal}\"
$secDef = \"#{$comboSecVal}\"
$textDef = \"#{$alarmTextVal}\"
$sun = #{$checkSunVal}
$mon = #{$checkMonVal}
$tue = #{$checkTueVal}
$wed = #{$checkWedVal}
$thu = #{$checkThuVal}
$fri = #{$checkFriVal}
$sat = #{$checkSatVal}"
    end
  end

  def sets2
    File.open('Sets2.rb', 'w') do |f|
      f.puts "$statusDef = \"#{$comboStatusVal}\"
$hourDef = \"#{$comboHourVal}\"
$minDef = \"#{$comboMinVal}\"
$secDef = \"#{$comboSecVal}\"
$textDef = \"#{$alarmTextVal}\"
$sun = #{$checkSunVal}
$mon = #{$checkMonVal}
$tue = #{$checkTueVal}
$wed = #{$checkWedVal}
$thu = #{$checkThuVal}
$fri = #{$checkFriVal}
$sat = #{$checkSatVal}"
    end
  end

  def sets3
    File.open('Sets3.rb', 'w') do |f|
      f.puts "$statusDef = \"#{$comboStatusVal}\"
$hourDef = \"#{$comboHourVal}\"
$minDef = \"#{$comboMinVal}\"
$secDef = \"#{$comboSecVal}\"
$textDef = \"#{$alarmTextVal}\"
$sun = #{$checkSunVal}
$mon = #{$checkMonVal}
$tue = #{$checkTueVal}
$wed = #{$checkWedVal}
$thu = #{$checkThuVal}
$fri = #{$checkFriVal}
$sat = #{$checkSatVal}"
    end
  end

  def sets4
    File.open('Sets4.rb', 'w') do |f|
      f.puts "$statusDef = \"#{$comboStatusVal}\"
$hourDef = \"#{$comboHourVal}\"
$minDef = \"#{$comboMinVal}\"
$secDef = \"#{$comboSecVal}\"
$textDef = \"#{$alarmTextVal}\"
$sun = #{$checkSunVal}
$mon = #{$checkMonVal}
$tue = #{$checkTueVal}
$wed = #{$checkWedVal}
$thu = #{$checkThuVal}
$fri = #{$checkFriVal}
$sat = #{$checkSatVal}"
    end
  end

  def saveButtonClick(event)
    $comboStatusVal = @comboStatus.get_value()
    $comboHourVal = @comboHour.get_value()
    $comboMinVal = @comboMin.get_value()
    $comboSecVal = @comboSec.get_value()
    $alarmTextVal = @alarmText.get_value()
    $checkSunVal = @checkSun.get_value()
    $checkMonVal = @checkMon.get_value()
    $checkTueVal = @checkTue.get_value()
    $checkWedVal = @checkWed.get_value()
    $checkThuVal = @checkThu.get_value()
    $checkFriVal = @checkFri.get_value()
    $checkSatVal = @checkSat.get_value()
    if $comboStatusVal == "On"
      $boolStatus = true
    elsif $comboStatusVal == "Off"
      $boolStatus = false
    else
      # Nothings
    end
    $whichAlarmVal = $whichAlarm.get_value()
    if $whichAlarmVal == 'Alarm # 1'
      sets1
    elsif $whichAlarmVal == 'Alarm # 2'
      sets2
    elsif $whichAlarmVal == 'Alarm # 3'
      sets3
    elsif $whichAlarmVal == 'Alarm # 4'
      sets4
    else
      # Nothing
    end
    bool1 = $onOff.fetch(0)
    bool2 = $onOff.fetch(1)
    bool3 = $onOff.fetch(2)
    bool4 = $onOff.fetch(3)
    if $whichAlarmVal == 'Alarm # 1'
      File.open('on-off.rb', 'w') do |f|
        f.puts "$onOff = [#{$boolStatus}, #{bool2}, #{bool3}, #{bool4}]"
      end
    elsif $whichAlarmVal == 'Alarm # 2'
      File.open('on-off.rb', 'w') do |f|
        f.puts "$onOff = [#{bool1}, #{$boolStatus}, #{bool3}, #{bool4}]"
      end
    elsif $whichAlarmVal == 'Alarm # 3'
      File.open('on-off.rb', 'w') do |f|
        f.puts "$onOff = [#{bool1}, #{bool2}, #{$boolStatus}, #{bool4}]"
      end
    elsif $whichAlarmVal == 'Alarm # 4'
      File.open('on-off.rb', 'w') do |f|
        f.puts "$onOff = [#{bool1}, #{bool2}, #{bool3}, #{$boolStatus}]"
      end
    else
      # Nothing
    end
  end
  def defButtonClick(event)
    results = []
    bool1 = $onOff.fetch(0)
    bool2 = $onOff.fetch(1)
    bool3 = $onOff.fetch(2)
    bool4 = $onOff.fetch(3)
    File.open('Defaults.rb', 'r').each { |line| results << line }
    if $whichAlarmVal == 'Alarm # 1'
      File.open('Sets1.rb', 'w') do |f1|
        f1.puts results
      end
    elsif $whichAlarmVal == 'Alarm # 2'
      File.open('Sets2.rb', 'w') do |f1|
        f1.puts results
      end
    elsif $whichAlarmVal == 'Alarm # 3'
      File.open('Sets3.rb', 'w') do |f1|
        f1.puts results
      end
    elsif $whichAlarmVal == 'Alarm # 4'
      File.open('Sets4.rb', 'w') do |f1|
        f1.puts results
      end
    else
      # Nothing
    end

    if $whichAlarmVal == 'Alarm # 1'
      File.open('on-off.rb', 'w') do |f|
        f.puts "$onOff = [false, #{bool2}, #{bool3}, #{bool4}]"
      end
    elsif $whichAlarmVal == 'Alarm # 2'
      File.open('on-off.rb', 'w') do |f|
        f.puts "$onOff = [#{bool1}, false, #{bool3}, #{bool4}]"
      end
    elsif $whichAlarmVal == 'Alarm # 3'
      File.open('on-off.rb', 'w') do |f|
        f.puts "$onOff = [#{bool1}, #{bool2}, false, #{bool4}]"
      end
    elsif $whichAlarmVal == 'Alarm # 4'
      File.open('on-off.rb', 'w') do |f|
        f.puts "$onOff = [#{bool1}, #{bool2}, #{bool3}, false]"
      end
    else
      # Nothing
    end
  end
end

class AlarmFrame < Frame
  def initialize()
    super(nil, -1, 'Alarm')
    @aPanel = Panel.new(self)
    @someText = StaticText.new(@aPanel, -1, "Time's up! Go to bed!",
DEFAULT_POSITION, DEFAULT_SIZE, ALIGN_CENTER)
    @stopButton = Button.new(@aPanel, -1, 'Ok')
    evt_button(@stopButton.get_id()) {|event|stopButtonClick(event)}
    @aPanelSizer = BoxSizer.new(VERTICAL)
    @aPanel.set_sizer(@aPanelSizer)
    @aPanel.sizer.add(@someText, 0, GROW|ALL, 2)
    @aPanel.sizer.add(@stopButton, 0, GROW|ALL, 2)
    Sound.play("beep4.wav", flags = SOUND_ASYNC|SOUND_LOOP)
    show()
  end

  def stopButtonClick(event)
    Sound.stop()
  end
end

class Alarm
  def initialize
    $bool1 = $onOff.fetch(0)
    $bool2 = $onOff.fetch(1)
    $bool3 = $onOff.fetch(2)
    $bool4 = $onOff.fetch(3)
  end
  def one
    if $bool1 == true
      require 'Sets1.rb'
      t = Time.now
      goOff0 = $hourDef
      goOff1 = $minDef
      goOff2 = $secDef
      sleepTime =
(goOff0.to_i*3600+goOff1.to_i*60+goOff2.to_i)-(t.strftime("%H").to_i*3600+t.strftime("%M").to_i*60+t.strftime("%S").to_i)
      sleep(sleepTime)
      AlarmFrame.new
    else
      # Nothings
    end
  end
  def two
    if $bool2 == true
      require 'Sets2.rb'
      t = Time.now
      goOff0 = $hourDef
      goOff1 = $minDef
      goOff2 = $secDef
      sleepTime =
(goOff0.to_i*3600+goOff1.to_i*60+goOff2.to_i)-(t.strftime("%H").to_i*3600+t.strftime("%M").to_i*60+t.strftime("%S").to_i)
      sleep(sleepTime)
      AlarmFrame.new
    else
      # Nothings
    end
  end
  def three
    if $bool3 == true
      require 'Sets3.rb'
      t = Time.now
      goOff0 = $hourDef
      goOff1 = $minDef
      goOff2 = $secDef
      sleepTime =
(goOff0.to_i*3600+goOff1.to_i*60+goOff2.to_i)-(t.strftime("%H").to_i*3600+t.strftime("%M").to_i*60+t.strftime("%S").to_i)
      sleep(sleepTime)
      AlarmFrame.new
    else
      # Nothings
    end
  end
  def four
    if $bool4 == true
      require 'Sets4.rb'
      t = Time.now
      goOff0 = $hourDef
      goOff1 = $minDef
      goOff2 = $secDef
      sleepTime =
(goOff0.to_i*3600+goOff1.to_i*60+goOff2.to_i)-(t.strftime("%H").to_i*3600+t.strftime("%M").to_i*60+t.strftime("%S").to_i)
      sleep(sleepTime)
      AlarmFrame.new
    else
      # Nothings
    end
  end
end

class MainApp < App
  def on_init
    SetsFrame.new
  end
end

_ = Thread.new {MainApp.new.main_loop()}
a = Thread.new {Alarm.new.one}
b = Thread.new {Alarm.new.two}
#c = Thread.new {Alarm.new.three}
#d = Thread.new {Alarm.new.four}
_.join
a.join
b.join
#c.join
#d.join
Posted by Alex Fenton (Guest)
on 15.04.2008 15:49
(Received via mailing list)
Hi Daniel

Thanks for the report. Unfortunately I couldn't test out your code
because it requires other files that you haven't included. We ask that
when posting a problem or bug, you simplify your code to demonstrate the
problem rather than just copying your enitre program.

http://wxruby.rubyforge.org/wiki/wiki.pl?MailingLists

I have a couple of suggestions on organisation and style that may help.
I think you could simplify your code quite a bit and that should help
iron out the bug.

My main one would be to use Wx::Timer rather than ruby Threads+sleep to
count down the time until the alarms go off. The way Ruby threads are
designed makes them ill-suited for many uses with GUI libraries, so
don't use them unless you really have to - and here, you don't.
>   def editButtonClick(event)
>     $whichAlarmVal = $whichAlarm.get_value()
>     if $whichAlarmVal == 'Alarm # 1'
>       require 'Sets1.rb'
>     elsif $whichAlarmVal == 'Alarm # 2'
>       require 'Sets2.rb'
>   
Here you could make your code a lot simpler by using client_data. This
allows you to associate any normal ruby object (eg an Alarm object) with
an item in a ComboBox. So when the user clicks the edit button, you just
find the Alarm object associated with the currently selected value in
the ComboBox, and start editing it. You would then be able to handle an
arbitrary number of Alarms.

http://wxruby.rubyforge.org/doc/controlwithitems.html
>     @dayText = StaticText.new(@aPanel, -1, "Days")
>     @checkSun = CheckBox.new(@aPanel, -1, "Sunday")
>     @checkMon = CheckBox.new(@aPanel, -1, "Monday")
>     @checkTue = CheckBox.new(@aPanel, -1, "Tuesday")
A CheckListBox might be better here:
http://wxruby.rubyforge.org/doc/checklistbox.html
>   def sets1
>     File.open('Sets1.rb', 'w') do |f|
>       f.puts "$statusDef = \"#{$comboStatusVal}\"
> $hourDef = \"#{$comboHourVal}\"
> $minDef = \"#{$comboMinVal}\"
There are much easier and safer ways to save an object with settings to
file. Look up "Marshal" or "YAML" for ruby - these will allow you to
save and load Alarms with no extra work.

> class Alarm
>   def initialize
>   
I would design your Alarm class to have attributes for the hour, minute
and second, an array for the days of the week, and a boolean to
represent whether it's on or off.

attr_accessor :hour, :minute, :second, :days, :active

Have a look at http://www.rubycentral.com/pickaxe/tut_classes.html

hth
alex
Posted by Daniel Washburn (anomaly)
on 22.04.2008 03:54
Thanks Alex, I'll look into that and see if I can't figure it out. As 
you can see I'm still a bit new to everything, so thanks again for your 
trouble.