Class: WinGui::Window
- Inherits:
-
Object
- Object
- WinGui::Window
- Defined in:
- lib/win_gui/window.rb
Overview
This class is a wrapper around window handle
Instance Attribute Summary collapse
-
#handle ⇒ Object
readonly
Returns the value of attribute handle.
Class Method Summary collapse
-
.lookup_window(opts) ⇒ Object
Looks up window handle using code specified in attached block (either with or without :timeout).
- .lookup_window_in_collection(opts, &collection_proc) ⇒ Object
-
.top_level(opts = {}) ⇒ Object
(also: find)
Finds top level window by title/class, returns wrapped Window object or nil (raises exception if asked to).
Instance Method Summary collapse
-
#child(opts = {}) ⇒ Object
Finds child window (control) by either control ID or window class/title.
-
#children ⇒ Object
Returns array of Windows that are descendants (not only DIRECT children) of a given Window.
-
#click(opts = {}) ⇒ Object
Emulates click of the control identified by opts (:id, :title, :class).
-
#close ⇒ Object
We alias convenience method shut_window (from Win::Gui::Window) with even more convenient window.close Please keep in mind that Win32 API has another function CloseWindow that merely MINIMIZES window.
-
#id ⇒ Object
Control ID associated with the window (only makes sense for controls).
-
#initialize(handle) ⇒ Window
constructor
A new instance of Window.
-
#method_missing(name, *args, &block) ⇒ Object
Since Window instances wrap actual window handles, they should directly support Win32 API functions manipulating these handles.
- #process ⇒ Object (also: #pid)
- #thread ⇒ Object
-
#title ⇒ Object
Alias for [get_]window_text.
-
#wait_for_close(timeout = CLOSE_TIMEOUT) ⇒ Object
Waits for this window to close with timeout (default CLOSE_TIMEOUT).
Constructor Details
#initialize(handle) ⇒ Window
Returns a new instance of Window.
6 7 8 |
# File 'lib/win_gui/window.rb', line 6 def initialize(handle) @handle = handle end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args, &block) ⇒ Object
Since Window instances wrap actual window handles, they should directly support Win32 API functions manipulating these handles. Therefore, when unsupported instance method is invoked, we check if WinGui responds to such method, and if yes, call it with our window handle as a first argument. This gives us all handle-related WinGui functions as instance methods for Window instances, like so:
window.visible?
This API is much more Ruby-like compared to:
visible?(window.handle)
Of course, if we invoke WinGui function that DOESN’T accept handle as a first arg this way, we are screwed. Call such functions only like this:
WinGui.function(*args)
TODO: Such setup is problematic if WinGui is included into Window ancestor chain. TODO: In this case, all WinGui functions become available as instance methods, and method_missing never fires. TODO: It may be a better solution to explicitly define all needed instance methods, TODO: instead of showing off cool meta-programming skillz. ;-)
198 199 200 201 202 203 204 205 |
# File 'lib/win_gui/window.rb', line 198 def method_missing(name, *args, &block) if WinGui.respond_to? name # puts "Window #{@handle} calling: #{name} #{@handle} #{args} &#{block}" WinGui.send(name, @handle, *args, &block) else super end end |
Instance Attribute Details
#handle ⇒ Object (readonly)
Returns the value of attribute handle.
10 11 12 |
# File 'lib/win_gui/window.rb', line 10 def handle @handle end |
Class Method Details
.lookup_window(opts) ⇒ Object
Looks up window handle using code specified in attached block (either with or without :timeout). Returns either Window instance (for a found handle) or nil if nothing found. Private method to dry up other window lookup methods
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/win_gui/window.rb', line 17 def lookup_window opts # :yields: index, position # Need this to avoid handle considered local var in begin..end block handle = yield if opts[:timeout] begin timeout(opts[:timeout]) do sleep SLEEP_DELAY until handle = yield end rescue Timeout::Error nil end end raise opts[:raise] if opts[:raise] && !handle Window.new(handle) if handle end |
.lookup_window_in_collection(opts, &collection_proc) ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/win_gui/window.rb', line 33 def lookup_window_in_collection opts, &collection_proc class_name = opts[:class] title = opts[:title] id = opts[:id] class_regexp = class_name.is_a? Regexp title_regexp = title.is_a? Regexp lookup_window(opts) do collection_proc.call.each do |handle| win = Window.new handle id_match = !id || win.id == id title_match = !title || win.title == title || title_regexp && win.title =~ title class_match = !class_name || win.class_name == class_name || class_regexp && win.class_name =~ class_name return win if class_match && title_match && id_match end nil end end |
.top_level(opts = {}) ⇒ Object Also known as: find
Finds top level window by title/class, returns wrapped Window object or nil (raises exception if asked to). If timeout option given, waits for window to appear within timeout, returns nil if it didn’t. Options:
- :title
-
window title (String or Regexp)
- :class
-
window class (String or Regexp)
- :timeout
-
timeout (seconds)
- :raise
-
raise this exception instead of returning nil if nothing found
63 64 65 66 67 68 69 |
# File 'lib/win_gui/window.rb', line 63 def top_level opts={} if opts[:class].is_a?(Regexp) || opts[:title].is_a?(Regexp) lookup_window_in_collection(opts) { WinGui.enum_windows } else lookup_window(opts) { WinGui.find_window opts[:class], opts[:title] } end end |
Instance Method Details
#child(opts = {}) ⇒ Object
Finds child window (control) by either control ID or window class/title. By default, only direct children are searched. Options:
- :id
-
integer control id (such as IDOK, IDCANCEL, etc)
- :title
-
window title (String or Regexp)
- :class
-
window class (String or Regexp)
- :indirect
-
search all descendants, not only direct children
- :timeout
-
timeout (seconds)
- :raise
-
raise this exception instead of returning nil if nothing found
84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/win_gui/window.rb', line 84 def child(opts={}) if opts[:indirect] self.class.lookup_window_in_collection(opts) { enum_child_windows } elsif opts[:class].is_a?(Regexp) || opts[:title].is_a?(Regexp) self.class.lookup_window_in_collection(opts) do enum_child_windows.select { |handle| child? handle } end else self.class.lookup_window opts do opts[:id] ? get_dlg_item(opts[:id]) : find_window_ex(0, opts[:class], opts[:title]) end end end |
#children ⇒ Object
Returns array of Windows that are descendants (not only DIRECT children) of a given Window
100 101 102 |
# File 'lib/win_gui/window.rb', line 100 def children enum_child_windows.map { |child_handle| Window.new child_handle } end |
#click(opts = {}) ⇒ Object
Emulates click of the control identified by opts (:id, :title, :class). Beware of keyboard shortcuts in button titles! So, use “&Yes” instead of just “Yes”. Returns screen coordinates of click point if successful, nil if control was not found
- :id
-
integer control id (such as IDOK, IDCANCEL, etc)
- :title
-
window title
- :class
-
window class
- :raise
-
raise this exception instead of returning nil if nothing found
- :position/point/where
-
location where the click is to be applied - default :center
- :mouse_button/button/which
-
mouse button which to click - default :right
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/win_gui/window.rb', line 114 def click(opts={}) control = child(opts) if control left, top, right, bottom = control.get_window_rect where = opts[:point] || opts[:where] || opts[:position] point = case where when Array where # Explicit screen coords when :random [left + rand(right - left), top + rand(bottom - top)] # Random point within control window else [(left + right) / 2, (top + bottom) / 2] # Center of a control window end WinGui.set_cursor_pos *point = opts[:mouse_button] || opts[:mouse] || opts[:which] down, up = ( == :right) ? [WinGui::MOUSEEVENTF_RIGHTDOWN, WinGui::MOUSEEVENTF_RIGHTUP] : [WinGui::MOUSEEVENTF_LEFTDOWN, WinGui::MOUSEEVENTF_LEFTUP] WinGui.mouse_event down, 0, 0, 0, 0 WinGui.mouse_event up, 0, 0, 0, 0 point else nil end end |
#close ⇒ Object
We alias convenience method shut_window (from Win::Gui::Window) with even more convenient
window.close
Please keep in mind that Win32 API has another function CloseWindow that merely MINIMIZES window. If you want to invoke this function, you can do it like this:
window.close_window
158 159 160 |
# File 'lib/win_gui/window.rb', line 158 def close shut_window end |
#id ⇒ Object
Control ID associated with the window (only makes sense for controls)
179 180 181 |
# File 'lib/win_gui/window.rb', line 179 def id get_dlg_ctrl_id end |
#process ⇒ Object Also known as: pid
172 173 174 |
# File 'lib/win_gui/window.rb', line 172 def process get_window_thread_process_id.last end |
#thread ⇒ Object
168 169 170 |
# File 'lib/win_gui/window.rb', line 168 def thread get_window_thread_process_id.first end |
#title ⇒ Object
Alias for [get_]window_text
164 165 166 |
# File 'lib/win_gui/window.rb', line 164 def title get_window_text end |
#wait_for_close(timeout = CLOSE_TIMEOUT) ⇒ Object
Waits for this window to close with timeout (default CLOSE_TIMEOUT).
146 147 148 149 150 |
# File 'lib/win_gui/window.rb', line 146 def wait_for_close(timeout=CLOSE_TIMEOUT) timeout(timeout) do sleep SLEEP_DELAY while window_visible? end end |