Ruby (Shoes) List box crash when populating from excel - ruby

I've got a problem when using Shoes. I'm basically trying to open an excel document and pass the names of the worksheets to a list_box. The following method is called on a button press after selecting a file. (This all works and the file opens)
exc = WIN32OLE::new('excel.Application')
excWB = exc.Workbooks.Open(xlsFile)
#excWS = Array::new
exc.visible = true
excWB.Worksheets.each { |ws| #excWS.push(ws.name) }
para #excWS
list_box :items=> #excWS
Not only do the names not show up in the list_box, the app crashes shortly after loading the box with no error. para #excWS shows the names of the worksheets with no problem.
What am I doing wrong?

it is the encoding that was the problem
This works
Shoes.app :width => 400, :height => 340, :size => 8 do
require 'win32ole'
exc = WIN32OLE::new('excel.Application')
excWB = exc.Workbooks.Open('C:/Shoes/0.r1514/test/book1.xls')
#excWS = Array::new
exc.visible = false
excWB.Worksheets.each { |ws| #excWS.push(ws.name.force_encoding("UTF-8")) }
list_box :items=> #excWS
exc.ActiveWorkbook.Close(0);
exc.Quit();
end

Related

ruby and Gtk::FontChooserDialog.new font size

I am using ruby 2.6.3, installed by compiling the source.
When using Gtk::FontChooserDialog.new, the default font size given is 10.
Is it possible to call Gtk::FontChooserDialog.new with a different size, such
as 24, so that I can avoid having to change the size each time I select a font.
Here is how I am doing things:
dialog = Gtk::FontChooserDialog.new(:title => "Select font",
:parent => self,
:action => Gtk::FileChooserAction::OPEN,
:buttons => [[Gtk::Stock::OPEN, Gtk::ResponseType::ACCEPT], [Gtk::Stock::CANCEL, Gtk::ResponseType::CANCEL]])
I have tried (in the argument list) :size => 24, :default_size => 24, etc. This does not work. I'm just guessing here. I have searched a lot, with no luck. I also looked in the gem sample dirs at test-gtk-font-chooser-dialog.rb and other files but no luck.
I am using Linux Mint Mate 19.1, installed a couple of weeks ago.
You need to set the size through a Pango.FontDescription. A short example in Python would be:
font_chooser = Gtk.FontChooserDialog.new(title = "Select font", parent = self)
font_description = Pango.FontDescription.new()
font_description.set_size(24 * Pango.SCALE)
font_chooser.set_font_desc(font_description)
EDIT
And here is a complete example in Ruby:
#!/usr/bin/ruby
'''
ZetCode Ruby GTK tutorial
This program runs a font dialog with a default (settable) font size.
Author: Jan Bodnar
Website: www.zetcode.com
Last modified: May 2014
'''
require 'gtk3'
require 'pango'
class RubyApp < Gtk::Window
def initialize
super
init_ui
end
def init_ui
set_title "Center"
signal_connect "destroy" do
Gtk.main_quit
end
button = Gtk::Button.new
button.set_label "Font"
button.signal_connect "clicked" do
dialog = Gtk::FontChooserDialog.new(:title => "Select font", :parent => self, :action => Gtk::FileChooserAction::OPEN, :buttons => [[Gtk::Stock::OPEN, Gtk::ResponseType::ACCEPT], [Gtk::Stock::CANCEL, Gtk::ResponseType::CANCEL]])
font_description = Pango::FontDescription.new
font_description.set_size 24 * Pango::SCALE
dialog.set_font_desc font_description
dialog.run
end
add button
set_default_size 300, 200
set_window_position Gtk::WindowPosition::CENTER
show_all
end
end
window = RubyApp.new
Gtk.main

Ruby Shoes GUI set port don't work with thread

If I don't use a thread, I can normally use #which_port.text.to_i in port declaration. If I use a thread, it looks like this statement #which_port.text.to_i don't work. I can only write port manually, e.g. 6000 and then my program works good. I have to use thread because my program freezes otherwise. Is any way able to use #which_port.text.to_i despite the use thread?
require 'socket'
require 'thread'
Shoes.app do
def write
#t = TCPSocket.new("xx.xx.xx.xx", #which_port.text.to_i)
loop do
msg = #t.recv(4096)
#pa1.text = #pa1.text + msg
end
end
#btn = button("button", width: 80, height: 50) do
window(left: 300, top: 300) do
#pa1 = para ""
#th1 = Thread.new { write }
end
end
#e_ln = edit_line(width: 320, height: 25, margin_top: 5)
#which_port = list_box :items => ["5000", "6000", "7000"],
:width => 120,
:choose => "5000" do |list|
end
end
end
Every time you launch a window you are launching a totally new app so variables in that new app are unknown to the other app, and those in the first app, the one that fired the window method are unknown to the new app ! Fortunately there is a owner method available in every Shoes app, in your case owner called inside the new app gives you a reference to the first app, the one that owns the new app !
One way to do what you want (Threading or not):
Shoes.app title: "Main Shoes app" do
def write(paragr)
msg = "#{self.inspect} === #{#which_port.text}"
paragr.text = paragr.text + msg
end
#btn = button("button", width: 80, height: 50) do
window(left: 300, top: 300, title: "Another Shoes app") do
#pa1 = para ""
Thread.new { owner.write(#pa1) }
end
end
#which_port = list_box :items => ["5000", "6000", "7000"],
:width => 120,
:choose => "5000" do |list|
end
end
You can also investigate the Shoes.APPS method which gives you back an array containing all opened app.
If this is Shoes 4 then it is very likely that the thread doesn't have access to the UI (only the main thread has access to the UI). You could try extracting the value beforehand and then passing it to write as an argument:
def write(port)
#...
end
port = #which_port.text.to_i
#th1 = Thread.new { write(port) }

Understanding Tk Listbox in ruby

I'm trying to make a small program to mung some data into usable form. One thing I'd like it to do is to be able to select some files and perform actions on them, so I thought i'd use the listbox object in Tk to do that. I want to be able to open a file and see its filename displayed in the listbox. As far as I've read this is precisely what using listvariable in the listbox is for. Yet when I run my code the listbox is never updated (although items already in the listvariable variable are displayed fine).
So here's a close to MWE for this. What am I doing wrong, and what fundamental idea have I misunderstood?
require 'tk'
require 'tkextlib/tile'
$path_list = []
$populate_list = TkVariable.new( $path_list )
def get_file
file = Tk.getOpenFile
file = open(file) unless file.empty?
path = File.basename(file, ".out")
if $path_list.include?(path)
Tk.messageBox(
'type' => "ok",
'icon' => "warning",
'title' => " - Minimum Working Example - ",
'message' => "This file has already been added! Nothing was added to the list"
)
else
$path_list.push(path)
end
end
root = TkRoot.new {title "- Minimum Working Example -"}
frame = Tk::Tile::Frame.new(root) {padding "3 3 12 12"}.grid( :sticky => 'nsew') # 'north south east west'
TkGrid.columnconfigure root, 0, :weight => 1; TkGrid.rowconfigure root, 0, :weight => 1
$file_listbox = Tk::Listbox.new(frame) {
listvariable $populate_list}.grid( :column => 1, :row => 0, :rowspan => 6)
Tk::Tile::Button.new(frame) {
width 15; text 'Open file...'; command {get_file}}.grid( :column => 0, :row => 1)
Tk.mainloop
Do I maybe have to write it in some other order?
Just add one line of code:
$populate_list.value = $path_list
under this one:
$path_list.push(path)
It works for me, although looks weird.
TkVariable create a proxy for you ruby variable, thus bridge your ruby var references with Tk widgets. But i don't know why changes in proxy var don't affect the var it points to. I'm not sure whether it should do that automatically.

How can I display the output of an array in Ruby Shoes?

I've got this as my code
openAll = File.open('N:\Josh\Blondie\db.txt')
allNumbers = Array.new
allNumbers=[]
openAll.each_line {|line|
allNumbers.push line
}
puts allNumbers
and I'd like to be able to display the output of this code in a new window with Ruby Shoes, I can't seem to get it to display anything though. The contents of the file are names and phone numbers.
Any ideas?
Here's an example of outputting text to a shoes window. Using a puts statement just outputs to the shell, not to the Shoes app.
Shoes.app :title => "GUI RAW file converter, for the CLI challenged",
:resizable => true do
background white
stack do
flow {
background gray, :height => 30
caption "Caption", :margin => 8, :stroke => white
stack {
para 'This is a fancy line I just printed to the window'
####### Here's an example line you could use to put out the array...
allNumbers.each do |number|
para "#{number}"
end
}
}
end
end
I guess you should use the method Kernel#alert instead of Kernel#puts.
http://shoesrb.com/manual/Built-in.html

How can I create a hidden button in Shoes?

In Shoes, I'd like to create a button that is initially hidden. I've tried passing :hidden => true as part of the button style, as well as calling #button.hide() after creating it, but it remains obstinately visible.
I've been able to work around this by not creating the button until I want it shown, but that requires checking to see if it already exists, rather than just using it.
Not at present. Buttons are still fairly unreliable in Shoes, especially on Windows. You can work around the issue by putting the button in a slot and hiding or showing the slot, but you may discover that the button won't hide again once it has been clicked once:
Shoes.app do
para 'This is some text.'
#flow = flow :width => 50, :hidden => true do
button 'a' do |btn|
alert 'Hello, World!'
end
end
button 'toggle' do
#flow.toggle
end
para 'Blah blah blah'
end
Luckily, there is a way out: slots. Slots can be given a click event, which makes them behave much as a button does. In fact, you can make fairly decent buttons out of slots.
Here's something I cobbled together. It lets you use the pesto_button method to generate buttons built on flows. You can modify it to fit your needs, including such things as using an image as the background, modifiable text (with auto-expanding width?), ability to change styles on the fly, etc:
class PestoButton < Widget
def initialize (text, opts = {})
#border_color = opts[:border_color] || gray
#border_width = opts[:border_width] || 3
#color = opts[:up_color] || gainsboro
#click_color = opts[:down_color] || #border_color
#width = opts[:width] || 80
#click = block_given? ? Proc.new { yield } : nil
#text = text
#visible = true
#flow = flow :width => #width do
background #color
border #border_color, :strokewidth => #border_width
para #text, :align => 'center'
end
#flow.click do
#flow.clear
#flow.append do
background #click_color
border #border_color, :strokewidth => #border_width
para #text, :align => 'center'
end
end
#flow.release do
#flow.clear
#flow.append do
background #color
border #border_color, :strokewidth => #border_width
para #text, :align => 'center'
#click.call if #click
end
end
end
def click
#click = block_given? ? Proc.new { yield } : nil
end
def show
#flow.show
end
def toggle
#flow.toggle
end
def hide
#flow.hide
end
end
Shoes.app do
para 'This is some text.'
#btn = pesto_button 'Click me!' do
alert 'Hello, World!'
end
button 'toggle' do
#btn.toggle
end
button 'new block' do
#btn.click do
alert 'Goodbye, World!'
end
end
button 'no block' do
#btn.click #Clears the click method
end
para 'Blah blah blah'
end

Resources