How to retrieve window handler of context menu in python - python

I need to retrieve window handler of Context menu for Windows desktop application automation. I used win32gui module to find the window handler, but it seems it does not work with the context menu.
import win32gui
# works fine with normal window
print(hex(win32gui.FindWindow("Micro", None)))
# does not work with context menu
print(hex(win32gui.FindWindow("Context", None)))

I did manage with these functions as workaround. The firs retrieve the window handle based on title, and the second retrieve the handle by the class name. This second approach can be used to find the context menu. Also this class can be used with Robot framework.
import win32gui
class AppTopLevelWindowFinder:
def find_window_handler_by_title(self, name):
windows = []
win32gui.EnumWindows(enumHandler, windows)
for next_window in windows:
if name in next_window[0]:
return next_window[2]
def find_window_handler_by_class(self, classname):
windows = []
win32gui.EnumWindows(enumHandler, windows)
for next_window in windows:
if classname in next_window[1]:
return next_window[2]
def enumHandler(hwnd, lwindow):
if win32gui.IsWindowVisible(hwnd):
lwindow.append((win32gui.GetWindowText(hwnd), win32gui.GetClassName(hwnd), hex(hwnd)))
newobj = AppTopLevelWindowFinder()
print(newobj.find_window_handler_by_title('Incoming Call'))
print(newobj.find_window_handler_by_class('32768'))

Related

Python : Add url to menu in appindicator

I'm trying to make a little application with appindicator and Gtk. My goal is to display a list of server with link to url of them.
Here is what I try :
from gi.repository import Gtk as gtk
from gi.repository import AppIndicator3 as appindicator
def main():
indicator = appindicator.Indicator.new(APPINDICATOR_ID, img, appindicator.IndicatorCategory.SYSTEM_SERVICES)
indicator.set_status(appindicator.IndicatorStatus.ACTIVE)
indicator.set_menu(build_menu())
gtk.main()
def build_menu():
menu = gtk.Menu()
value = "label"
item = gtk.MenuItem()
button = gtk.LinkButton("http://url/host/id", label=value)
button.show()
item.add(button)
item.show()
menu.append(item)
menu.show_all()
return menu
if __name__ == "__main__":
main()
That's working and I have no errors. But wen I launch application, I've only menu, with items but no link.
I've seen many exemple with gtk.Window but nothing with a menu for appindicator.
Is there a way to have link in this menu ?
Thanks
I've found a way to do that. I'm not sure it's the best way, but it works.
Instead of create a LinkItem, I've made a function for open url:
def open_url(source):
webbrowser.open("http://url/host/id")
And I call it after, with connect :
item.connect("activate", open_url)
When I run my app and click on my item, it opens url as expected. Here is part of code working:
def build_menu():
menu = gtk.Menu()
value = "label"
item = gtk.MenuItem(value)
item.connect("activate", open_url)
menu.append(item)
menu.show_all()
return menu
As I see in many post on web, appindicator has limited functions compared to normal Gtk application.

TKInter checkbox variable is always 0

I'm using Python's TkInter module for a GUI. Below is a simple checkbox code.
def getCheckVal():
print cbVar.get()
windowTime=Tk.Tk()
cbVar = Tk.IntVar()
btnC = Tk.Checkbutton(windowTime, text="Save", variable = cbVar, command=getCheckVal)
btnC.grid()
windowTime.mainloop()
This code works fine. Each time I tick the checkbox, I get 1, else 0.
However, when I run the same code in a function that is called from another TkInter command (when a button is pressed), it stops working. I always get 0 as the value.
class GUIMainClass:
def __init__(self):
'''Create the main window'''
self.window = Tk.Tk()
def askUser(self):
def getCheckVal():
print cbVar.get()
windowTime=Tk.Tk()
cbVar = Tk.IntVar()
btnC = Tk.Checkbutton(windowTime, text="Save", variable = cbVar,
command=getCheckVal)
btnC.grid()
windowTime.mainloop()
def cmdWindow(self):
frameShow=Tk.Frame(self.window)
frameShow.grid()
btnSwitch = Tk.Button(frameShow, text='Show Plots', command=self.askUser)
btnSwitch.grid()
self.window.mainloop()
GUIObj=GUIMainClass()
GUIObj.cmdWindow()
This is very unusual. What could be going wrong?
EDIT: I've used 2 mainloops because I want a separate window (windowTime) to open up when I click "Show Plots" button. This new window should have the checkbox in it.
Your windowTime, cbVar, etc. variables are defined in the function's local scope. When askUser() completes execution, those values are thrown away. Prepend self. to them to save them as instance variables.
There should only be one mainloop() in your program, to run the main Tkinter root object. Try putting it as the very last line in the program. I recommend doing some reading on Effbot for how to set up a Tkinter application.
I'm not sure what all you're trying to do, but one problem is that the TK.IntVar called cbVar that you create in your askUser() method will be deleted when the function returns, so you need to attach it to something that will still exist after that happens. While you could make it a global variable, a better choice would be to make it an attribute of something more persistent and has a longer "lifespan".
Another likely issue is that generally there should only be one call to mainloop() in a single Tkinter application. It appears what you want to do is display what is commonly known as a Dialog Window, which Tkinter also supports. There's some standard ones built-in, plus some more generic classes to simplify creating custom ones. Here's some documentation I found which describes them in some detail. You may also find it helpful to look at their source code.
In Python 2 it's in the /Lib/lib-tk/tkSimpleDialog.py file and
in Python 3 the code's in a file named /Lib/tkinter/simpledialog.py.
Below is code that takes the latter approach and derives a custom dialog class named GUIButtonDialog from the generic one included the Tkinter library which is simply named Dialog.
try:
import Tkinter as Tk # Python 2
from tkSimpleDialog import Dialog
except ModuleNotFoundError:
import tkinter as Tk # Python 3
from tkinter.simpledialog import Dialog
class GUIButtonDialog(Dialog):
"""Custom one Button dialog box."""
def __init__(self, btnText, parent=None, title=None):
self.btnText = btnText
Dialog.__init__(self, parent, title)
def getCheckVal(self):
print(self.cbVar.get())
def body(self, master):
"""Create dialog body."""
self.cbVar = Tk.IntVar()
self.btnC = Tk.Checkbutton(master, text=self.btnText, variable=self.cbVar,
command=self.getCheckVal)
self.btnC.grid()
return self.btnC # Return the widget to get inital focus.
def buttonbox(self):
# Overridden to suppress default "OK" and "Cancel" buttons.
pass
class GUIMainClass:
def __init__(self):
"""Create the main window."""
self.window = Tk.Tk()
def askUser(self):
"""Display custom dialog window (until user closes it)."""
GUIButtonDialog("Save", parent=self.window)
def cmdWindow(self):
frameShow = Tk.Frame(self.window)
frameShow.grid()
btnSwitch = Tk.Button(frameShow, text='Show Plots', command=self.askUser)
btnSwitch.grid()
self.window.mainloop()
GUIObj = GUIMainClass()
GUIObj.cmdWindow()

Setting Application Menu name in GTK+/Python (fixing "Unknown Application Name")

When running GTK+ apps under Ubuntu 12.04, how do you set the application name that is displayed in the Application-level menu?
Here's an example app:
from gi.repository import GLib, Gtk, Gio
import sys
class MyApp(object):
def __init__(self):
GLib.set_application_name('My App')
self.app = Gtk.Application.new('org.example.test', 0)
self.app.connect('startup', self.on_app_startup)
self.app.connect('activate', self.on_app_activate)
self.app.connect('shutdown', self.on_app_shutdown)
def run(self, argv):
self.app.run(argv)
def on_app_startup(self, app):
self.window = Gtk.ApplicationWindow.new(app)
self.window.set_default_size(640, 480)
self.window.set_title('AppMenu Demo')
app.add_window(self.window)
# # App menu
app_menu = Gio.Menu()
section = Gio.Menu()
item = Gio.MenuItem.new('Quit', 'app.quit')
item.set_attribute_value("accel", GLib.Variant("s", "<Control>Q"))
section.append_item(item)
app_menu.append_section(None, section)
app.set_app_menu(app_menu)
# # Menu bar
menu_bar = Gio.Menu()
submenu = Gio.Menu()
section = Gio.Menu()
section.append_item(Gio.MenuItem.new('Help', 'app.help'))
submenu.append_section(None, section)
menu_bar.append_submenu('Help', submenu)
app.set_menubar(menu_bar)
action = Gio.SimpleAction.new('quit', None)
action.connect('activate', self.on_quit)
app.add_action(action)
def on_app_activate(self, app):
self.window.show_all()
def on_app_shutdown(self, app):
pass
def on_quit(self, action, data=None):
self.app.quit()
if __name__ == '__main__':
app = MyApp()
app.run(sys.argv)
If you run this code under Ubuntu 12.04, it pops up a window labeled "AppMenu Demo"; the control bar at the top of the screen shows this name as well. If you move your mouse to the control bar, two pulldown menus are displayed; the app menu, and a "Help" menu.
This is all fine - except that the name of the Application menu is "Unknown Application Name". I can't find any way to alter this name. GLib.set_application_name(name) doesn't do it. How do you set the application name?
Or: is this a case where GTK+ is ahead of what Ubuntu supports? Google searches for "unknown application name" point at a range of bug reports and merged patches, which suggests to me that this might be an area of current development, rather than stable API. A quick survey of apps installed in Ubuntu shows that most apps have a "File" menu, but nothing that would be identified as an "app" menu of the type that GTK+ seems to support. Should I just abandon app menus until they're better supported at an OS level?
It is a ubuntu specific/unity specific/ancient gtk+ 3.4.x/gtk+ 3.6.x bug.
With somewhat current (gtk+ 3.10.7 and Cinnamon 2.014 as DE) it works just fine.

hide window from MS windows taskbar

Using pyGtk I created a window without decoration. The Window is hidden from task bar and top of all windows. On linux it works fine, but on MS Windows window sometimes it hides under some other window and always has "python.exe" the taskbar in windows.
Image representing my problem:
How can I hide this "python.exe" window from taskbar?
My code:
class Infowindow(gtk.Window):
'''
Klasa okienka informacyjnego
'''
def __init__(self, json, index, destroy_cb, device):
gtk.Window.__init__(self)
self.size_x = 260+48
self.size_y = 85
self.separator_size = 10
self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_SPLASHSCREEN)
self.set_decorated(False)
self.set_property('skip-taskbar-hint', True)
self.set_opacity(1)
self.set_keep_above(True)
self.add_events(gtk.gdk.BUTTON_PRESS_MASK)
self.connect("enter-notify-event", self.__on_hover)
self.connect("leave-notify-event", self.__on_leave)
self.connect("button_press_event", self.__on_click)
self.set_size_request(self.size_x, self.size_y)
color = gtk.gdk.color_parse('#f3f3f3')
self.modify_bg(gtk.STATE_NORMAL, color)
self.expanded = False
self.index = index
self.destroy_cb = destroy_cb
self.json = json['data']
self.system_info = False if 'system' not in self.json or not self.json['system'] else True
self.device = device
f = gtk.Frame()
self.move_window(index) #move window to specified place
self.box_area = gtk.VBox()
self.box_area.set_spacing(10)
f.add(self.box_area)
self.add(f)
self.show_all()
Again thanks David Heffernan. Works perfect!
For people who want a full solution in python.
Name your windowin a characteristic way for example: 'alamakota'
Use find_window('alamakota'),
With given handler use hide_from_taskbar(handler)
Last use set_topmost(handler)
Window is hidden from taskbar and it's alwoays on top.
I know it's not a beatyfull code, but works fine on windows XP and above.
import ctypes
import win32gui
import win32api
from win32con import SWP_NOMOVE
from win32con import SWP_NOSIZE
from win32con import SW_HIDE
from win32con import SW_SHOW
from win32con import HWND_TOPMOST
from win32con import GWL_EXSTYLE
from win32con import WS_EX_TOOLWINDOW
#staticmethod
def find_window(name):
try:
return win32gui.FindWindow(None, name)
except win32gui.error:
print("Error while finding the window")
return None
#staticmethod
def hide_from_taskbar(hw):
try:
win32gui.ShowWindow(hw, SW_HIDE)
win32gui.SetWindowLong(hw, GWL_EXSTYLE,win32gui.GetWindowLong(hw, GWL_EXSTYLE)| WS_EX_TOOLWINDOW);
win32gui.ShowWindow(hw, SW_SHOW);
except win32gui.error:
print("Error while hiding the window")
return None
#staticmethod
def set_topmost(hw):
try:
win32gui.SetWindowPos(hw, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE)
except win32gui.error:
print("Error while move window on top")
You have two options to remove a window from the taskbar:
Add the WS_EX_TOOLWINDOW extended window style. But this has other consequences and I cannot say whether or not they are serious.
Give the window an owner that is not visible. This allows you freedom to use whatever window styles and extended styles you wish, but does involve more work.
It's natural that your window will go beneath other windows. That's how windows works. If you want to make your window appear on top, show it with HWND_TOPMOST.
I've no idea how any of this is (or is not) implemented under PyGtk. I've just given you the Win32 answer!
Win32 solution provided in the other answer is not very easy and it does not play well with the GtkWindow::show method. A simple solution now in Gtk3 is:
win->set_type_hint(Gdk::WindowTypeHint::WINDOW_TYPE_HINT_UTILITY); //This works
win->set_skip_taskbar_hint(); //This does not guarantee to work

In Tkinter how to pass a called function as argument?

In Tkinter for constructing the menubar with the <menu_item>.add_command() we need a string for the accelerator argument which will create the hotkey binding for a command.
I created a method, which is checking if the user's platform is Mac or other, and if it is, then returns the Command key string combined with the other keys.
But it doesn't work -> the menu is building, if I click on the menu-item it is working, but not working with the hot-keys. ALthough I can see the ⌘ + N in the menu..
My first thought is, that the self.hot_key() method is not called while passed as an argument..
import sys
import Tkinter
class app(object):
def __init__(self):
self.gui = Tkinter.Tk()
self.gui.minsize(width=640, height=320)
menu = Tkinter.Menu(self.gui)
filemenu = Tkinter.Menu(menu, tearoff=0)
filemenu.add_command(
label = 'New',
command = self.New,
accelerator = self.hot_key('n')
)
menu.add_cascade(
label = 'File',
menu = filemenu
)
self.gui.config(menu=menu)
self.text = Tkinter.Text(self.gui)
self.text.pack(expand=Tkinter.YES, fill=Tkinter.BOTH)
def hot_key(self, *keys):
super_key = 'Command' if sys.platform == 'darwin' else 'Control'
return '{super}+{keys}'.format(super=super_key, keys='+'.join(keys))
def New(self):
print "I'm working!"
App = app()
App.gui.mainloop()
According to this page,
The "accelerator" option is used to indicate the menu accelerator that
should be associated with this menu. This does not actually create the
accelerator, but only displays what it is next to the menu item. You
still need to create a binding for the accelerator yourself.
So your accelerator keyword argument is working as designed -- the Command-N symbol appears in your menu.
As mgilson suggests in a comment, you can use bind_all to get the keyboard combination to actually do something.
self.gui.bind_all("<Command-n>", lambda event: self.New())

Categories