How to keep widget at bottom of frame? - ruby

My main window launches a top-level window with a sub-frame (to browse/select a directory) along with 'load' and 'add directory' buttons at the bottom. The 'add directory' button deletes all the directory entry subframes (but leaves the buttons), checks that there are no duplicates directories entered or empty strings, and recreates subframes for valid entries and creates another one left blank.
The problem is that when I click the 'add directory' button, the buttons end up on top. Is there a way to fix the buttons to the bottom of the window?
In Main class:
def add_directory
dir_window = TkToplevel.new(#root) {title 'Directories'}
dir_frame = Tk::Tile::Frame.new(dir_window) {padding "3 3 12 12"}.grid(:sticky => 'nsew')
DirectoryFrame.show(dir_frame)
loadDirectoriesButtonClicked = proc {load_files}
Tk::Tile::Button.new(dir_frame) {text 'Load directories'; command loadDirectoriesButtonClicked}.grid(:column=>0, :sticky=>'s')
addDirButtonClicked = proc {DirectoryFrame.show(dir_frame)}
Tk::Tile::Button.new(dir_frame) {text '+'; width 2; command addDirButtonClicked}.grid(:column=>1, :sticky=>'sw')
end
In directory frame class:
class DirectoryFrame < Tk::Tile::Frame
##directory_frames = []
##directories = []
def self.show(parent_frame)
if !(##directory_frames.nil? || ##directory_frames.empty?)
directories
remove_frames(parent_frame)
end
##directories.delete("")
if !(##directories.nil? || ##directories.empty?)
##directories.each do |dir|
dir_frame = DirectoryFrame.new(parent_frame)
dir_frame.directory = dir
##directory_frames << dir_frame
end
end
##directory_frames << DirectoryFrame.new(parent_frame)
refresh
end
def self.refresh
##directory_frames.each_with_index do |dir_frame, index|
dir_frame.grid(:row=>index, :sticky=>'ew')
end
end

If you don't specify which row to put a widget on when you grid it in, Tk picks the row with number one larger than the current largest used row number. This is often just fine, but is wrong for you. Instead, you should explicitly put your buttons in a row with a large number (e.g., 1000), and then have a counter of inserted rows that you use to decide which new explicit row to do the insertion on.
+--------------------+
| row 1 |
+--------------------+
| row 2 |
+--------------------+
| row 3 |
+--------------------+
| ... empty ... |
+--------------------+
| row 1000 |
+--------------------+
The other alternative is to put the buttons in a frame with another inner frame that holds the gridded space that you are adding rows into.
+----------------------+
|+--------------------+|
|| row 1 ||
|+--------------------+|
|| row 2 ||
|+--------------------+|
|| row 3 ||
|+--------------------+|
+----------------------+
| buttons |
+----------------------+
Either technique will work.

Related

how to update terminal values in realtime

I have the following asc table:
+---------------------------------------------+
| Report |
+----------+----------+-------------+---------+
| Store | Total |
+----------+----------+-------------+---------+
| A | 2723 |
| B | 7277 |
+----------+----------+-------------+---------+
I need to update the total while threre are updates running on my database.
How can I do that?
I already have the method that gets updated total.
But how can I persist the total on the terminal screen?
You can achieve this using the following gems
https://github.com/ruby/curses
https://github.com/tj/terminal-table
Example :
require 'terminal-table'
require "curses"
Curses.init_screen
Curses.crmode
Curses.noecho
Curses.stdscr.keypad = true
begin
x = 0
y = 0
loop do
table = Terminal::Table.new do |t|
t << ['Random 1', Random.rand(1...10)]
t.add_row ['Random 1', Random.rand(10...100)]
end
Curses.setpos(x, y)
output = table.render.to_s
Curses.addstr(output)
Curses.refresh
sleep 1
end
ensure
close_screen
end

wxpython grid: multiple cell edit (ala Excel)

I'm looking for a way for a user to edit data in bulk in a wxPython grid, a little like in Excel when you select a range, type data and press shift-Enter. This is a simplified version of my grid:
class MyGrid(gridlib.Grid):
def __init__(self, panel):
gridlib.Grid.__init__(self, panel)
self.Bind(gridlib.EVT_GRID_CELL_CHANGE, self.onEditCell)
self.Bind(gridlib.EVT_GRID_RANGE_SELECT, self.onSelection)
def onSelection(self, event):
if self.GetSelectionBlockTopLeft() == []:
self.selected_row_number = 0
self.selected_col_number = 0
else:
self.selected_row_number = self.GetSelectionBlockBottomRight()[0][0] - self.GetSelectionBlockTopLeft()[0][0] + 1
self.selected_col_number = self.GetSelectionBlockBottomRight()[0][1] - self.GetSelectionBlockTopLeft()[0][1] + 1
print self.selected_row_number, self.selected_col_number
def onEditCell(self,event):
print self.selected_row_number, self.selected_col_number
The issue seems to be that the onEditCell event overwrites the previous selection. So I can select e.g. a four by four block in the grid, and onSelection will print 4 4. But when I start typing and press Enter, onEditCell will print 0,0 as if only the cell I'm editing was selected. How can I keep a "memory" of how many cells are selected? Thank you,
Answering my own question: I can get it to work with an ugly hack that doesn't seem like the right way to do things:
def onSelection(self, event):
self.previous_selected_row_number = self.selected_row_number
self.previous_selected_col_number = self.selected_col_number
if self.GetSelectionBlockTopLeft() == []:
self.selected_row_number = 0
self.selected_col_number = 0
else:
self.selected_row_number = self.GetSelectionBlockBottomRight()[0][0] - self.GetSelectionBlockTopLeft()[0][0] + 1
self.selected_col_number = self.GetSelectionBlockBottomRight()[0][1] - self.GetSelectionBlockTopLeft()[0][1] + 1
print self.selected_row_number, self.selected_col_number
print self.previous_selected_row_number, self.previous_selected_col_number
def onEditCell(self,event):
print self.previous_selected_row_number, self.previous_selected_col_number
If anyone can think of a better way...

WebFocus, two title columns and merging cells

If i have a table in a WebFocus Raport design
+--------+---------+--------+---------+
| left_1 | right_1 | left_2 | right_2 |
+--------+---------+--------+---------+
| v11 | p11 | v21 | v21 |
+--------+---------+--------+---------+
| v12 | p12 | v22 | v22 |
....
How to do a such table with syllabus column titles:
+-------+-------+-------+-------+
| One | Two |
+-------+-------+-------+-------+
| left | right | left | right |
+-------+-------+-------+-------+
| v11 | p11 | v21 | v21 |
+-------+-------+-------+-------+
| v12 | p12 | v22 | v22 |
....
Thank you
Sorry for the delay of the answer :)
To rename columns, with the AS command. Example:
TABLE FILE SYSTABLE
PRINT NAME
COMPUTE LEFT1/A3 = 'v11'; AS 'left';
COMPUTE RIGHT1/A3 = 'p11'; AS 'right';
COMPUTE LEFT2/A3 = 'v21'; AS 'left';
COMPUTE RIGHT2/A3 = 'p21'; AS 'right';
IF RECORDLIMIT EQ 10
END
To put the heading columns, you can work with the ACROSS command but it will be more tricky that if u use simply SUBHEAD. With the same example:
TABLE FILE SYSTABLE
PRINT NAME NOPRINT
COMPUTE LEFT1/A3 = 'v11'; AS 'left';
COMPUTE RIGHT1/A3 = 'p11'; AS 'right';
COMPUTE LEFT2/A3 = 'v21'; AS 'left';
COMPUTE RIGHT2/A3 = 'p21'; AS 'right';
IF RECORDLIMIT EQ 10
ON TABLE SUBHEAD
"<+0>One<+0> Two"
ON TABLE PCHOLD FORMAT HTML
ON TABLE SET HTMLCSS ON
ON TABLE SET STYLE *
UNITS=IN, PAGESIZE='Letter',
LEFTMARGIN=0.500000, RIGHTMARGIN=0.500000,
TOPMARGIN=0.500000, BOTTOMMARGIN=0.500000,
SQUEEZE=ON, GRID=OFF, ORIENTATION=LANDSCAPE, $
TYPE=REPORT,FONT='ARIAL',SIZE=9,$
TYPE=TABHEADING,HEADALIGN=BODY,$
TYPE=TABHEADING, LINE=1, ITEM=1, COLSPAN=2, SQUEEZE=ON,$
TYPE=TABHEADING, LINE=1, ITEM=2, COLSPAN=2, SQUEEZE=ON,$
ENDSTYLE
END
Hope it helps!
I'm not entirely sure if you load the headers as a field or if that is the field name
But this might help you
Define fields
TITL1/A3 = 'One';
TITL2/A3 = 'Two';
BLANK/A1 = '';
Edit the Left and Right title fields to remove the _1 or _2
Print the fields BY BLANK NOPRINT
Add
ON BLANK SUBHEAD
"
You can also add more rows to the subhead if you need more titles
You can easily do it by embedding HTML/CSS scripts in report(.fex) file.
just add the HTML/css code at the end of the file.
For eg.
-HTMLFORM BEGIN // to start styling your generated report table with HTML/CSS
TABLE tr
td:first-child // applies on 1st row ONLY.It can be td or th.
{
colspan = "2"; //to merge 2 columns
}
-HTMLFORM END //end HTML.
So the first row must have two cells having title "ONE" and "TWO"(in your case), and both cells must have property of colspan = "2"
Also you can refer:
Colspan propery from here
manipulating first row of table from here
Second option is to write the whole code in a file and save it in .htm/.html format and just insert the file in to WEBFOCUS(.fex) file.For eg.
-HTMLFORM BEGIN
-INCLUDE HTML_FILE.HTML
-HTMLFORM END
Hope it helps.Thanks.

In Wxpython How do i Insert an image into an Ultimatelistctrl column?

I am curious as to how one would go about inserting an image from a specific directory into a specific row/column in an Ultimatelistctrl
MainFrame.ultimatelist = ULC.UltimateListCtrl( self.panel , agwStyle = wx.LC_REPORT | wx.LC_VRULES | wx.LC_HRULES , pos = (10,100) , size = (1240 , 520) )
#-------------------------------------------------------------
MainFrame.FirstColumn = ULC.UltimateListItem()
MainFrame.FirstColumn._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_CHECK
MainFrame.FirstColumn._image = []
MainFrame.FirstColumn._format = 1
MainFrame.FirstColumn._kind = 1
MainFrame.FirstColumn._text = ""
MainFrame.ultimatelist.InsertColumnInfo( 1 , MainFrame.FirstColumn)
MainFrame.arrowicon = wx.Image( "arrow.jpg" , wx.BITMAP_TYPE_ANY).ConvertToBitmap()
MainFrame.ultimatelist.SetImage( 0 , MainFrame.arrowicon )
Cheers, It has been really bothering me :)
All the magic is in the wxPython demo. You need to create an UltimateListCtrl.PyImageList. Then add wx.Bitmap instances to it. Next, you need to tell your UltimateListItem() object to use an item from the image list. In the demo, look for "info._image" to see how it's done. You can download the wxPython demo from the wxPython website.

merge rows csv by id ruby

I have a .csv file that, for simplicity, is two fields: ID and comments. The rows of id's are duplicated where each comment field had met max char from whatever table it was generated from and another row was necessary. I now need to merge associative comments together thus creating one row for each unique ID, using Ruby.
To illustrate, I'm trying in Ruby, to make this:
ID | COMMENT
1 | fragment 1
1 | fragment 2
2 | fragment 1
3 | fragment 1
3 | fragment 2
3 | fragment 3
into this:
ID | COMMENT
1 | fragment 1 fragment 2
2 | fragment 1
3 | fragment 1 fragment 2 fragment 3
I've come close to finding a way to do this using inject({}) and hashmap, but still working on getting all data merged correctly. Meanwhile seems my code is getting too complicated with multiple hashes and arrays just to do a merge on selective rows.
What's the best/simplest way to achieve this type of row merge? Could it be done with just arrays?
Would appreciate advice on how one would normally do this in Ruby.
Keep the headers and use group by ID:
rows = CSV.read 'comment.csv', :headers => true
rows.group_by{|row| row['ID']}.values.each do |group|
puts [group.first['ID'], group.map{|r| r['COMMENT']} * ' '] * ' | '
end
You can use 0 and 1 but I think it's clearer to use the header field names.
With the following csv file, tmp.csv
1,fragment 11
1,fragment 21
2,fragment 21
2,fragment 22
3,fragment 31
3,fragment 32
3,fragment 33
Try this (demonstrated using irb)
irb> require 'csv'
=> true
irb> h = Hash.new
=> {}
irb> CSV.foreach("tmp.csv") {|r| h[r[0]] = h.key?(r[0]) ? h[r[0]] + r[1] : r[1]}
=> nil
irb> h
=> {"1"=>"fragment 11fragment 21", "2"=>"fragment 21fragment 22", "3"=>"fragment 31fragment 32fragment 33"}

Resources