我创建了一个相对简单的Ruby脚本,允许用户从下拉框中选择一个项目。我这样做是通过创建一个Internet Explorer的实例,然后从ruby自动化它。
最好我想进一步使用UI并更改ICON,甚至可能更改窗口标题。
注意:我确实意识到这是“重新发明轮子”,因为有很多宝石可以帮助创建GUI。但是,遗憾的是我需要一个纯标准Ruby的解决方案。
这是我目前的代码:
# To learn how to use win32 libraries see here:
# http://phrogz.net/programmingruby/lib_windows.html
# https://ruby-doc.org/stdlib-2.2.0/libdoc/win32ole/rdoc/WIN32OLE.html
require 'win32ole'
require 'Win32API'
def combobox(sTitle, aOptions)
ie = WIN32OLE.new('InternetExplorer.Application')
#set various options
ie.resizable = false
ie.toolbar = false
ie.registerAsDropTarget = false
ie.statusBar = false
ie.navigate("about:blank")
sleep(0.1) until !ie.busy
ie.width=450
ie.height=190
ie.left = ie.document.parentWindow.screen.width / 2 - 200
ie.top = ie.document.parentWindow.screen.height / 2 - 75
#Set window icon (C++)
# HANDLE icon = LoadImage(fgDisplay.Instance, "c:\\icon.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
# SendMessage(instance, (UINT)WM_SETICON, ICON_BIG, (LPARAM)icon);
#icon = LoadImage(null,"my/file/name/as/string.ico",IMAGE_ICON=1,0 or 32,0 or 32,LR_DEFAULTSIZE||LR_LOADFROMFILE) #LR_DEFAULTSIZE = 0x00000040; LR_LOADFROMFILE = 0x00000010;
#SendMessage(HWND, WM_SETICON, ICON_BIG, icon)
#User32 LoadImage: https://msdn.microsoft.com/en-us/library/windows/desktop/ms648045(v=vs.85).aspx
#User32 SendMessageA: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644950(v=vs.85).aspx
#define WM_SETICON 0x0080
#ICON_BIG 1
#ICON_SMALL 0
#Define constants:
_IMAGE_ICON = 1
_LR_LOADFROMFILE = 0x00000040
_LR_DEFAULTSIZE = 0x00000010
_WM_SETICON = 0x0080
_ICON_BIG = 1
_ICON_SMALL = 0
#Set icon
icoPath = "C:\Users\jwa\Desktop\Icons\toxic.ico" #"l" --> "v"
icon = Win32API.new("user32","LoadImage",["v","p","i","i","i","i"],"p").call(0,icoPath, _IMAGE_ICON, 0,0, _LR_DEFAULTSIZE || _LR_LOADFROMFILE)
puts icon
Win32API.new("user32","SendMessageA",["l","i","i","p"],"i").call(ie.hwnd,_WM_SETICON,_ICON_SMALL,icon)
#Set window content
s = "
<html>
<head>
<title>#{sTitle}</title>
</head>
<script type=\"text/javascript\">window.bWait=true</script>
<script>
submitForm = function(){
document.url = document.getElementById(\"entries\").selectedIndex
}
</script>
<body bgColor=Silver>
<center>
<b>#{sTitle}<b>
<p>
<select id=entries size=1 style='width:250px'>
<option selected></option>"
#Add options
aOptions.each do |item|
s += "<option>#{item}</option>"
end
s += " </select>
<p>
<button id=but0 onclick='submitForm()'>OK</button>
</center>
</body>
</html>"
ie.document.writeLn(s)
ie.document.body.scroll = "no"
ie.document.body.style.borderStyle = "outset"
ie.document.body.style.borderWidth = "3px"
ie.document.all.entries.Focus
ie.visible = true
#Bring window to front
Win32API.new("user32","BringWindowToTop",["l"],"i").call(ie.hwnd)
#wait till url not about:blank
begin
until (ie.document.url!="about:blank") do
sleep(0.1)
end
rescue
return -1
end
#Get id and hide ie
id=ie.document.url
id=id.to_i
ie.visible = false
#Return id-1
return id-1
end
一般情况下,脚本可以运行,但我还没有使用自定义图标。
#Set icon
icoPath = "C:\Users\jwa\Desktop\Icons\toxic.ico" #"l" --> "v"
icon = Win32API.new("user32","LoadImage",["v","p","i","i","i","i"],"p").call(0,icoPath, _IMAGE_ICON, 0,0, _LR_DEFAULTSIZE || _LR_LOADFROMFILE)
puts icon ### ==> 0
Win32API.new("user32","SendMessageA",["l","i","i","p"],"i").call(ie.hwnd,_WM_SETICON,_ICON_SMALL,icon) ### ==> Doesn't do anything (likely due to icon==0)
这段代码有什么明显的错误吗?
注意:同样,我很乐意为此使用类似于ffi的Gem,但不幸的是,这是不可能的。
答案 0 :(得分:2)
很好的解决方案,我迟到了,但想向您展示我用于此类任务的内容。我曾经使用green_shoes来完成这些任务,但厌倦了控件的非原生外观和其他限制(例如没有网格)。
另一方面,有一个强大的自动键,具有非常好的GUI,但很难编码(肯定与Ruby相比)。
所以我尝试了autohotkey.dll,它允许你使用autohotkey代码以及Ruby的GUI。效果很好。 您需要下载并注册dll。 https://autohotkey.com/board/topic/39588-autohotkeydll/
这里是一个下拉选择的例子(还有一个真正的组合)。
require 'win32ole'
def choose_from_dropdown *list
selections = list.join('|')
code = %Q{
Gui, Add, DropDownList, r50 w200 vChoice, #{selections}
Gui, Show, x131 y91 h67 w227, Make your choice
Hotkey,Enter,a1,ON
Return
GuiClose:
Gui, Submit, nohide
return
a1:
Gui, Submit, nohide
return
}
ahk = WIN32OLE.new("AutoHotkey.Script")
ahk.AhkTextDll(code)
choice = nil
while ahk.ahkReady == 1 do
sleep 1
choice = ahk.ahkgetvar('Choice')
if choice && choice != ""
ahk.ahkTerminate
return choice
end
end
rescue => e
puts e.message
puts e.backtrace
end
puts choose_from_dropdown %w{one two three}
在这样的列表中,我喜欢使用向上和向下键进行滚动并使用Enter键确认,这是我实现的,也可以使用Ok按钮等实现其他实现。
答案 1 :(得分:0)
\
中转义字符串中的字符,所以:
#Set icon
icoPath = "C:\Users\jwa\Desktop\Icons\toxic.ico"
实际上返回"C:UsersjwaDesktopIconstoxic.ico"
当然不是文件路径......我需要这样做:
#Set icon
icoPath = "C:\\Users\\jwa\\Desktop\\Icons\\toxic.ico"
糟糕。此外,似乎win32api在ruby 中使用“p”指针。因此,在seticon语句中使用win32api返回的句柄,即
Win32API.new("user32","SendMessageA",[args*],"i")
args *的最后一个参数应该是一个长"l"
而不是一个指针。像这样:
Win32API.new("user32","SendMessageA",["l","i","i","l"],"i").call(ie.hwnd,_WM_SETICON,_ICON_SMALL,icon)
同样重要的是要注意,您应该同时拨打_ICON_SMALL
和_ICON_BIG
。 _ICON_SMALL
是窗口中的图标,_ICON_BIG
是alt-tab菜单中的图标。
#Define constants:
_IMAGE_ICON = 1
_LR_LOADFROMFILE = 0x00000040
_LR_DEFAULTSIZE = 0x00000010
_WM_SETICON = 0x0080
_ICON_BIG = 1
_ICON_SMALL = 0
#Set icon
icoPath = "C:\\Users\\jwa\\Desktop\\Icons\\toxic.ico" #"l" --> "v"
icon = Win32API.new("user32","LoadImageA",["l","p","l","l","l","l"],"p").call(0,icoPath, _IMAGE_ICON, 0,0, _LR_DEFAULTSIZE | _LR_LOADFROMFILE | 0)
Win32API.new("user32","SendMessageA",["l","i","i","l"],"i").call(ie.hwnd,_WM_SETICON,_ICON_SMALL,icon) # affects title bar
Win32API.new("user32","SendMessageA",["l","i","i","l"],"i").call(ie.hwnd,_WM_SETICON,_ICON_BIG,icon) # affects alt-tab