Home » Eclipse Projects » Standard Widget Toolkit (SWT) » Use dynamic models to quickly develop SWT applications
|
Re: Use dynamic models to quickly develop SWT applications [message #1848526 is a reply to message #1847131] |
Tue, 07 December 2021 02:17 |
Andy Maleh Messages: 75 Registered: March 2020 Location: Montreal, Quebec, Canada |
Member |
|
|
Using GUI designer tools is usually for either beginners or non-software-engineers. Expert software engineers are slowed down by GUI designers, so they resort to writing very well-designed minimalistic code instead while relying on Design Patterns and Domain Specific Languages.
Actually, if you really want to quickly develop SWT applications, just use Glimmer DSL for SWT.
I built a Metronome with it in less than 10 minutes for the initial version:
https://andymaleh.blogspot.com/2021/03/glimmer-metronome-hello-canvas.html
Tetris took me 1 day for the initial working version:
https://github.com/AndyObtiva/glimmer_tetris
Here is an article series that can walk anyone through that:
https://planetruby.github.io/gems/glimmer/05-glimmer-tetris-playfield.html
I was later able to reuse the same Tetris code to run online on the web via Glimmer DSL for Opal:
https://github.com/AndyObtiva/glimmer-dsl-opal#tetris
I built a children's programming language based on a simplified version of Logo in about one week for the first working version:
https://github.com/AndyObtiva/dcr
I've built a complete professional project management app with Glimmer DSL for SWT in about 11 days, taking full advantage of built-in bidirectional data-binding, which is only a single line for data-binding a table (unlike JFace Data-Binding syntax, which takes pages of code. Nonetheless, JFace Data-Binding is certainly the inspiration for data-binding features in Glimmer DSL for SWT):
https://github.com/AndyObtiva/are-we-there-yet
The single data-binding code line needed to bind the table data:
items bind(Task, :list), column_properties(:project_name, :task_type, :name, :start_date, :end_date, :duration, :priority)
Extra lines are added to declaratively configure the table for editing/sorting (no manual code is needed for using TableEditor or sorting TableItems).
Full table code is here:
https://github.com/AndyObtiva/are-we-there-yet/blob/master/app/views/are_we_there_yet/task_table.rb
table(:multi, :full_selection) { |table_proxy|
# TODO Make resizing table columns auto-resize form fields
@project_name_table_column = table_column {
text 'Project'
width CONFIG[:table_column_width_hint]
editor :combo
}
table_column {
text 'Type'
width CONFIG[:table_column_width_hint]
editor :combo
}
table_column {
text 'Task'
width CONFIG[:table_column_width_hint]
}
table_column {
text 'Start Date'
width CONFIG[:table_column_width_hint]
editor :c_date_drop_down, property: :start_at
}
table_column {
text 'End Date'
width CONFIG[:table_column_width_hint]
editor :c_date_drop_down, property: :end_at
}
table_column {
text 'Duration (hours)'
width CONFIG[:table_column_width_hint]
editor :combo, :read_only
sort_property :duration_in_hours
}
table_column {
text 'Priority'
width CONFIG[:table_column_width_hint]
editor :combo, :read_only
sort_property :priority_sort
}
additional_sort_properties :project_name, :task_type, :start_date, :duration_in_hours, :name, :priority_sort, :end_date
items bind(Task, :list), column_properties(:project_name, :task_type, :name, :start_date, :end_date, :duration, :priority)
table_proxy.sort_by_column @project_name_table_column
on_control_resized {
window_width = body_root.swt_widget.shell.bounds.width
columns = body_root.swt_widget.columns
new_column_width = window_width.to_f / columns.size
columns.each do |column|
column.width = new_column_width
end
}
on_mouse_up { |event|
table_proxy.edit_table_item(event.table_item, event.column_index)
}
on_menu_detected { |event|
column_x = event.x - event.widget.shell.bounds.x
column_y = 0
@column_index = nil
# TODO offload this to a method on TableProxy
@sort_by_menu_item.swt_widget.text = 'Sort' unless OS.windows?
@remove_task_menu_item.swt_widget.text = 'Remove Task'
if !event.widget.items.empty?
@remove_task_menu_item.swt_widget.text = 'Remove Tasks' if swt_widget.selection.size > 1
table_item = event.widget.items.first
@column_index = event.widget.column_count.times.to_a.detect do |ci|
table_item.getBounds(ci).contains(column_x, column_y)
end
@sort_by_menu_item.swt_widget.text = "Sort by #{swt_widget.columns[@column_index].text}" if @column_index && OS.windows?
end
}
menu {
@remove_task_menu_item = menu_item {
text "Remove Task"
on_widget_selected {
swt_widget.selection.map(&:data).each(&:destroy)
}
}
unless OS.windows?
@sort_by_menu_item = menu_item {
text 'Sort'
on_widget_selected { |event|
body_root.sort_by_column(body_root.table_column_proxies[@column_index]) if @column_index
}
}
end
}
}
Best of all, JRuby already has built-in support for Dynamic Models as you can use OpenStruct to set properties dynamically and observe them for View/Model bidirectional data-binding if you really want Dynamic Models. Most of the time, you get away just fine with Simple Models though.
Glimmer was originally an Eclipse incubation project, but later became an MIT-license free and open-source project on GitHub.
EclipseCon / EclipseWorld / Agile Conference Speaker
Open-Source Software Author of Glimmer DSL for SWT
[Updated on: Tue, 07 December 2021 02:28] Report message to a moderator
|
|
|
Goto Forum:
Current Time: Tue May 07 02:29:04 GMT 2024
Powered by FUDForum. Page generated in 5.03351 seconds
|