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).
-
.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
- #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. ;-)
173 174 175 176 177 178 179 180 |
# File 'lib/win_gui/window.rb', line 173 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 |
.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
- :class
-
window class
- :timeout
-
timeout (seconds)
- :raise
-
raise this exception instead of returning nil if nothing found
41 42 43 |
# File 'lib/win_gui/window.rb', line 41 def top_level(opts={}) lookup_window(opts) { WinGui.find_window opts[:class], opts[:title] } 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
- :class
-
window class
- :indirect
-
search all descendants, not only direct children
- :timeout
-
timeout (seconds)
- :raise
-
raise this exception instead of returning nil if nothing found
TODO: add the ability to nail indirect children as well
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/win_gui/window.rb', line 58 def child(opts={}) if opts[:indirect] self.class.lookup_window opts do found = children.find do |child| (opts[:id] ? child.id == opts[:id] : true) && (opts[:class] ? child.class_name == opts[:class] : true) && (opts[:title] ? child.title == opts[:title] : true) end found.handle if found 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
77 78 79 |
# File 'lib/win_gui/window.rb', line 77 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
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/win_gui/window.rb', line 91 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
135 136 137 |
# File 'lib/win_gui/window.rb', line 135 def close shut_window end |
#id ⇒ Object
Control ID associated with the window (only makes sense for controls)
154 155 156 |
# File 'lib/win_gui/window.rb', line 154 def id get_dlg_ctrl_id end |
#process ⇒ Object
149 150 151 |
# File 'lib/win_gui/window.rb', line 149 def process get_window_thread_process_id.last end |
#thread ⇒ Object
145 146 147 |
# File 'lib/win_gui/window.rb', line 145 def thread get_window_thread_process_id.first end |
#title ⇒ Object
Alias for [get_]window_text
141 142 143 |
# File 'lib/win_gui/window.rb', line 141 def title get_window_text end |
#wait_for_close(timeout = CLOSE_TIMEOUT) ⇒ Object
Waits for this window to close with timeout (default CLOSE_TIMEOUT).
123 124 125 126 127 |
# File 'lib/win_gui/window.rb', line 123 def wait_for_close(timeout=CLOSE_TIMEOUT) timeout(timeout) do sleep SLEEP_DELAY while window_visible? end end |