Python win32 API to mimic AutoHotKey Tooltip UI - python

I would like to mimic the tooltip functionality found in AutoHotKey.
AutoHotKey code:
infoTooltip() {
MouseGetPos, xPos, yPos, winId
PixelGetColor, color, %xPos%, %yPos%, RGB
WinGetTitle, winTitle, ahk_id %winId%
ToolTip "%winTitle%"`n%xPos% %yPos% %color%
}
Looks like this when called inside a loop and will follow mouse around:
References found from googling:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms632680(v=vs.85).aspx
How to use Windows ToolTip Control without bounding to a tool
My Python code attempt so far:
import win32con, win32gui
from win32api import GetModuleHandle
from commctrl import (TOOLTIPS_CLASS, TTS_ALWAYSTIP, TTS_NOPREFIX, TTM_ADDTOOL, TTM_SETMAXTIPWIDTH)
class TooltipWindow:
def __init__(self):
win32gui.InitCommonControls() # Loads COMCTL32.DLL (Shell Common Controls Library)
self.hwnd = win32gui.CreateWindowEx(
win32con.WS_EX_CLIENTEDGE | win32con.WS_EX_TOPMOST,
TOOLTIPS_CLASS,
"MyTooltipWindow",
win32con.WS_POPUP | TTS_ALWAYSTIP | TTS_NOPREFIX | win32con.WS_BORDER,
win32con.CW_USEDEFAULT,
win32con.CW_USEDEFAULT,
win32con.CW_USEDEFAULT,
win32con.CW_USEDEFAULT,
None,
None,
GetModuleHandle(None),
None
)
win32gui.SendMessage(self.hwnd, TTM_ADDTOOL, None, ???)
tooltip = TooltipWindow()
I have no idea how to translate the TOOLINFO struct to the lparam argument. Also, going in blind trying to get most of this code working as this is my first real win32gui project.
Any help is appreciated, thank you!

Have you considered instead doing a Dll import? It's definitely worth lugging around the .dll it if you are planning on using more authotkey functionality.
import ctypes
dll = ctypes.cdll.LoadLibrary("AutoHotkey.dll")
dll.ahktextdll(u"")
dll.ahkExec('MouseGetPos, xPos, yPos, winId' \
'\n PixelGetColor, color, %xPos%, %yPos%, RGB' \
'\n WinGetTitle, winTitle, ahk_id %winId%' \
'\n ToolTip "%winTitle%"`n%xPos% %yPos% %color%')

Related

Using COM interface in python

I want to show/hide tabtip.exe on demand. I was able to toggle it using code given to me here.
import win32gui
from ctypes import HRESULT
from ctypes.wintypes import HWND
from comtypes import IUnknown, GUID, COMMETHOD
import comtypes.client
class ITipInvocation(IUnknown):
_iid_ = GUID("{37c994e7-432b-4834-a2f7-dce1f13b834b}")
_methods_ = [
COMMETHOD([], HRESULT, "Toggle",
( ['in'], HWND, "hwndDesktop" )
)
]
dtwin = win32gui.GetDesktopWindow();
ctsdk = comtypes.client.CreateObject("{4ce576fa-83dc-4F88-951c-9d0782b4e376}", interface=ITipInvocation)
ctsdk.Toggle(dtwin);
comtypes.CoUninitialize()
But it toggle the keyboard, I want show and hide functions separate. I am trying to use this method but can't understand how can I implement it in python. Any guide would be appreciated.
Side Note:
I am new to COM and win32Api. I have been reading a lot MSDN documentation and posts on it. But there are very few available regarding these topic. If you know any good tutorial on "Using COM interface in python", it would be grateful.

run programmatically an ipyvuetify button

Assume I have a code with a button coded in ipyvuetify
v_btn_load = vue.Btn(class_='mx-2 light-red darken-1',
children=[vue.Icon(left=True, children=['get_app']),'Load data'])
def on_click_load(widget, event, data):
#pseudo code: load file
print("button run")
v_btn_load.on_event('click', on_click_load)
How do I run (click) programmatically the v_btn_load button?
v_btn_load.click() does not work
Thanks
the "on_click_load" is still a local python function, so you can simple access it in your script. Just fill out the variables you do not need with dummies (probably widget and event) and fill the data variable according to your needs.
If you need some input from the client, than it is more difficult. I know no way to remote control the client side. The only thing I got working so far is to extend VuetifyTemplate with a private class and specify some JS code to be run when 'Mounted'. This will run the code on display, but is not the same as triggering a click act:
Here is a simple example which directly copies the content of a variable to the local clipboard without any display element:
import ipyvuetify as v
from traitlets import Unicode, observe
class toClipboard(v.VuetifyTemplate):
"""Copies a given string directly to the users clipboard.
Parameters:
clipboardValue - The value to offer for copying to the clipboard
Example:
tunnel = toClipboard(clipboardValue='VALUE_TO_COPY')
Upon change of the variable 'clipboardValue', it's content will be automatically pushed to the clipboard
"""
clipboardValue = Unicode('').tag(sync=True)
template = Unicode('''
<script>
export default {
mounted () {
var tmpElement = $('<textarea>').val(this.clipboardValue).appendTo('body').select();
document.execCommand('copy');
$(tmpElement).remove();
},
}
</script>''').tag(sync=True)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.observe(self.pushToClipboard, names=('clipboardValue'))
display(self)
def pushToClipboard(self, change):
display(self)
As an additional bonus this example uses the observe function of traitlets to redisplay the JS as soon as the value of the variable changes. This is a cheap workaround to create a bit similar behaviour.
I use the example above not in real GUIs, but as a lazy way in a Jupyther Notebook to automatically copy the result of a calculation to my local clipboard.
looking at the description of the v.Btn class I found this :
| ----------------------------------------------------------------------
| Methods inherited from ipyvue.VueWidget.Events:
|
| fire_event(self, event, data)
|
| on_event(self, event_and_modifiers, callback, remove=False)
I then assume that
v_btn_load.fire_event('click', None)
should do trick

How to install cairo and rsvg for python

I understand that Stackoverflow is for help with code, but I figured I'd ask anyways.
I found from the post here that it is possible to put a .svg file into a tkinter window, but after days of searching, I still can't find any place where I could install cairo and rsvg from.
I am currently using Windows 10 with python 3.6.
EDIT:
I have found out how to install cairo and rsvg. Cairo is working but
rsvg is not. I have managed to put SVGs in Tkinter with cairo and not rsvg, though. For
anyone curious about this, you may want to check post out:
Putting .SVG images into tkinter Frame.
Thanks in advance.
Edit: Ok, so pip won't work for installing pycairo. Found that out.
And the other options haven't worked for me either. I am about to be
away from my computer, but I'll give you some of the things I found.
This
This
and
This
Sorry I couldn't be more help. Hope you figure it out!
First, use pip install pycairo
Unfortunately, rsvg is unavailable for windows, but cairographics.org have a simple wrapper.
Save the following as rsvg.py in the same folder as your script:
#some code to give rsvg.render_cairo(ctx) ability
#on windows.
import os
try:
import rsvg
WINDOWS=False
except ImportError:
print"Warning, could not import 'rsvg'"
if os.name == 'nt':
print "Detected windows, creating rsvg."
#some workarounds for windows
from ctypes import *
l=CDLL('librsvg-2-2.dll')
g=CDLL('libgobject-2.0-0.dll')
g.g_type_init()
class rsvgHandle():
class RsvgDimensionData(Structure):
_fields_ = [("width", c_int),
("height", c_int),
("em",c_double),
("ex",c_double)]
class PycairoContext(Structure):
_fields_ = [("PyObject_HEAD", c_byte * object.__basicsize__),
("ctx", c_void_p),
("base", c_void_p)]
def __init__(self, path):
self.path = path
error = ''
self.handle = l.rsvg_handle_new_from_file(self.path,error)
def get_dimension_data(self):
svgDim = self.RsvgDimensionData()
l.rsvg_handle_get_dimensions(self.handle,byref(svgDim))
return (svgDim.width,svgDim.height)
def render_cairo(self, ctx):
ctx.save()
z = self.PycairoContext.from_address(id(ctx))
l.rsvg_handle_render_cairo(self.handle, z.ctx)
ctx.restore()
class rsvgClass():
def Handle(self,file):
return rsvgHandle(file)
In your script, do from rsvg import * and when you need to use it, run:
rC = rsvgClass()
h = rC.Handle("YOUR-FILE-HERE.svg")
s = cairo.ImageSurface(cairo.FORMAT_ARGB32, 100, 100)
ctx = cairo.Context(s)
h.render_cairo(ctx)

Is there a way to use ribbon toolbars in Tkinter?

I am yet to decide what language and tools to use for my next project. I would love to use python, but I would like to implement ribbon toolbars. Some work has been done in Tk (http://www.ellogon.org/petasis/bibliography/Tcl2010/TkRibbon.pdf), but it looks like it hasn't been implemented in tkinter yet. Is there anything I can do to get this to work?
You need to create a wrapper for this and get a version of the binary you can use. I built this for use with Python 3.4 and copied it to tkribbon1.0-x86_64.zip. You should unzip this in the Python/tcl subdirectory so the version of tcl used by python can load it.
A minimal wrapper looks like this:
from tkinter import Widget
from os import path
class Ribbon(Widget):
def __init__(self, master, kw=None):
self.version = master.tk.call('package','require','tkribbon')
self.library = master.tk.eval('set ::tkribbon::library')
Widget.__init__(self, master, 'tkribbon::ribbon', kw=kw)
def load_resource(self, resource_file, resource_name='APPLICATION_RIBBON'):
"""Load the ribbon definition from resources.
Ribbon markup is compiled using the uicc compiler and the resource included
in a dll. Load from the provided file."""
self.tk.call(self._w, 'load_resources', resource_file)
self.tk.call(self._w, 'load_ui', resource_file, resource_name)
if __name__ == '__main__':
import sys
from tkinter import *
def main():
root = Tk()
r = Ribbon(root)
name = 'APPLICATION_RIBBON'
if len(sys.argv) > 1:
resource = sys.argv[1]
if len(sys.argv) > 2:
name = sys.argv[2]
else:
resource = path.join(r.library, 'libtkribbon1.0.dll')
r.load_resource(resource, name)
t = Text(root)
r.grid(sticky=(N,E,S,W))
t.grid(sticky=(N,E,S,W))
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(1, weight=1)
root.mainloop()
main()
Running this uses the resources built-in to the tkribbon dll and looks like . The complicated bit is going to be getting some Ribbon markup resources into a DLL for loading.
You can use this example to load ribbons from existing applications. For instance, python Ribbon.py c:\Windows\System32\mspaint.exe MSPAINT_RIBBON will load up the ribbon resource from mspaint. The resource name in this case has to be included as the default is APPLICATION_RIBBON. For your own ribbon, using uicc to build a .rc file, then rc /r file.rc to produce a .res file and finally link -dll -out:file.dll file.rc -noentry -machine:AMD64 seems to work to produce a resource only DLL that works with this extension.

Show Explorer's properties dialog for a file in Windows

Is there an easy way to show the properties dialog for a file in Windows using Python?
I'm trying to show the same window that pops up when you right click a file in Explorer and choose Properties.
The way to do this is to call the Windows ShellExecuteEx() API passing the properties verb. There are various high-level Python wrappers of this but I have not succeeded in getting any of them to work with the properties verb. Instead I would use good old ctypes.
import time
import ctypes
import ctypes.wintypes
SEE_MASK_NOCLOSEPROCESS = 0x00000040
SEE_MASK_INVOKEIDLIST = 0x0000000C
class SHELLEXECUTEINFO(ctypes.Structure):
_fields_ = (
("cbSize",ctypes.wintypes.DWORD),
("fMask",ctypes.c_ulong),
("hwnd",ctypes.wintypes.HANDLE),
("lpVerb",ctypes.c_char_p),
("lpFile",ctypes.c_char_p),
("lpParameters",ctypes.c_char_p),
("lpDirectory",ctypes.c_char_p),
("nShow",ctypes.c_int),
("hInstApp",ctypes.wintypes.HINSTANCE),
("lpIDList",ctypes.c_void_p),
("lpClass",ctypes.c_char_p),
("hKeyClass",ctypes.wintypes.HKEY),
("dwHotKey",ctypes.wintypes.DWORD),
("hIconOrMonitor",ctypes.wintypes.HANDLE),
("hProcess",ctypes.wintypes.HANDLE),
)
ShellExecuteEx = ctypes.windll.shell32.ShellExecuteEx
ShellExecuteEx.restype = ctypes.wintypes.BOOL
sei = SHELLEXECUTEINFO()
sei.cbSize = ctypes.sizeof(sei)
sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_INVOKEIDLIST
sei.lpVerb = "properties"
sei.lpFile = "C:\\Desktop\\test.txt"
sei.nShow = 1
ShellExecuteEx(ctypes.byref(sei))
time.sleep(5)
The reason I put in the call to sleep is that the properties dialog is shown as a window in the calling process. If the Python executable terminates immediately following the call to ShellExecuteEx, then there is nothing there to service the dialog and it does not show.

Categories