display a menu bar icon on osx - python

I'd like to have my application display an icon in OSX menu bar (top of screen where Growl sits). How would I do this using Python? (I understand this is not possible using wxPython but I am not after a wxPython specific solution).
Thanks!

An implementation of this may be found at:
https://web.archive.org/web/20080709014939/http://the.taoofmac.com/space/blog/2007/04/22/1745
http://the.taoofmac.com/space/blog/2007/04/22/1745

The API for displaying icons in the OS X menubar is called NSStatusItem. It's going to be difficult or impossible to use from a wxPython application, though -- you will probably have to write your application using PyObjC to use it effectively.

The rumps package makes this very easy. Here's an example from rumps's README:
import rumps
class AwesomeStatusBarApp(rumps.App):
#rumps.clicked("Preferences")
def prefs(self, _):
rumps.alert("jk! no preferences available!")
#rumps.clicked("Silly button")
def onoff(self, sender):
sender.state = not sender.state
#rumps.clicked("Say hi")
def sayhi(self, _):
rumps.notification("Awesome title", "amazing subtitle", "hi!!1")
if __name__ == "__main__":
AwesomeStatusBarApp("Awesome App").run()

Related

How to make my Program Display Always on top

Program Info & Problem
I have created a Python Program Using Pygame Module which displays the Ads on the monitor.
It shows The Ad on screen But as soon as I launch different applications like kodi or vlc or chrome, etc. It goes behind those applications.
The Problem is: The program runs but behind those applications if these applications are launched after my Ad Program.
Ideal Working
Program Laucnhed
Ad Displayed on screen
Launched Other Application
The Program still displayes the ad on top of screen.
System Info
OS: Linux - Ubuntu 20
Language: Python
Module: Pygame, Pymovie, GTK3+
Architecture: amd64
Desktop Enviroment: OpenBOX
Code Launch: CLI using a bash script which launches the python program of advertisment.
Sample Screenshot of Advertiesment
Please Help!
Thank you.
Looks like the best answer I can find is from this outdated website (https://www.mail-archive.com/pygtk#daa.com.au/msg01370.html)
they say to use code below, it should work on all OSs...things are never that easy
transient.set_transient_for(main_window)
Alternatively I have four other answers lol
Taken from (How to keep a python window on top of all others (python 3.1))
stackoverflow user pyfunc says for windows you can just do
import win32gui
import win32con
win32gui.SetWindowPos(hWnd, win32con.HWND_TOPMOST, 0,0,0,0,
win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)
Since this only works for windows I think you should try python-tinker, I believe it works on linux
root = Tk()
root.wm_attributes("-topmost", 1)
Also whatnick says you can use PyGTK
gtk.Window.set_keep_above
reference: How to make python window run as "Always On Top"?
Let me know if any of these work for you, I will keep looking for a better answer.
I think PyWinCtl can make the trick in most cases. You can invoke alwaysOnTop() once for your window, or you can call it inside your loop to assure it stays on top after other apps open. Check this:
import tkinter as tk
import pywinctl as pwc
class Window(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.overrideredirect(True)
self.geometry('300x200')
self.config(background='black')
self.attributes('-alpha', 0.5)
self.label = tk.Label(text="Hello World!")
self.label.pack(fill=tk.BOTH, expand=1)
self.wait_visibility()
self.window = pwc.Window(int(self.frame(), base=16))
# Call it once at the beginning of your program...
try:
self.window.alwaysOnTop()
except:
pass
self.counter = 0
self.display()
def display(self):
if self.state() == "normal":
try:
# ... or call it repeatedly to assure it stays on top
self.window.alwaysOnTop()
except:
# On Linux, sometimes it takes more time to recognize the new window
self.window = pwc.Window(int(self.frame(), base=16))
self.label.config(text=str(self.counter))
self.counter += 1
self.after(1000, self.display)
root = Window()
root.mainloop()

Program in wxPython and VPython

I wrote program in wxPython and VPython, but I have huge problem: Module VPython not always run. If I run program in Interpreter, program run more often , than after compilation. Code never returns any errors. I try on the other computers, program is the same.
Win7
Python 2.7.5 32bit
wxPython 2.9.4
VPython 6.0.5
import visual as v
import wx
class Maintest(v.window):
def InitUI(self):
fileMenu = wx.Menu()
self.menubar.Append(fileMenu, '&Plik')
self.menubar.Remove(0)
def asd(self, scene):
v.box()
def main():
w = Maintest(menus=True, title="program", x=100, y=100, width=1024, height=600)
w.InitUI()
scene = v.display(window=w, x=0, y=0, width=600, height=600, up=(0,0,1), background=(1,1,1), foreground = (0,1,0), forward=(-1,-1,-1))
w.asd(scene)
while True:
v.rate(60)
if __name__ == '__main__':
main()
All is OK: http://imageshack.us/photo/my-images/199/tpp.png/
Not OK: http://imageshack.us/photo/my-images/689/akun.png/
It is only the part of main program, but problem is the same.
What is wrong? What I should to do?
I will be gratefull for answer.
With Win7 Python 2.7.5 64bit wxPython 2.9.4 VPython 6.0.5 I cannot get the program to fail. The fact that the problem is not entirely reproducible (and is entirely nonreproducible by me) suggests the possibility that the graphics driver needs to be updated. VPython uses the OpenGL 3D graphics library, which is sensitive to driver issues.
Only a guess but you may have let something out:
import wx
app = wx.App(redirect=True)
top = wx.Frame(None, title="Hello World", size=(300,200))
top.Show() # you need this
app.MainLoop() # you need this
I had a similar issue, or at least one with similar symptoms, and found that it was dependant on the position of the mouse at launch time (see full description here).
The solution was to call Hide and Show in succession after the display was created.
These calls need to be made to the panel fed to the display object.
win.panel.Hide()
win.panel.Show()

How to make click-through windows PyQt

I would like to make a window in PyQt that you can click through; ie click on a window and the click is passed through so you can interact with whatever is behind it, while the window remains on top. An example of the effect I am trying to achieve is like the notifications on Ubuntu which appear in the top-right hand corner by default, which you can click through.
I would like to be able to do this in PyQt ideally; if not, my platform is linux but windows solutions are also welcome!
Cheers for the help in advance! I've been giving this a bit of thought and research, it would be great to be able to do this.
EDIT: I am trying to make a window you can use like tracing paper for the window behind
Here is a solution on Windows using PyQt4.
You need to override the eventFilter in the Front widget (on Windows it is winEvent) and then forward the events to the Back window.
I'm not completely sure, but there must be a similar approach that can be used on other platforms (instead of winEvent, maybe x11Event?)
Good luck!
from PyQt4 import QtCore, QtGui
import win32api, win32con, win32gui, win32ui
class Front(QtGui.QPushButton):
def __init__(self,text="",whndl=None):
super(Front,self).__init__(text)
self.pycwnd = win32ui.CreateWindowFromHandle(whndl)
# install an event filter for Windows' messages. Forward messages to
# the other HWND
def winEvent(self,MSG):
# forward Left button down message to the other window. Not sure
# what you want to do exactly, so I'm only showing a left button click. You could
if MSG.message == win32con.WM_LBUTTONDOWN or \
MSG.message == win32con.WM_LBUTTONUP:
print "left click in front window"
self.pycwnd.SendMessage(MSG.message, MSG.wParam, MSG.lParam)
return True, 0 # tells Qt to ignore the message
return super(Front,self).winEvent(MSG)
class Back(QtGui.QPushButton):
def __init__(self,text=""):
super(Back,self).__init__(text)
self.clicked.connect(self.onClick)
def onClick(self):
print 'back has been clicked'
def main():
a = QtGui.QApplication([])
back = Back("I'm in back...")
back.setWindowTitle("I'm in back...")
back.show()
# Get the HWND of the window in back (You need to use the exact title of that window)
whndl = win32gui.FindWindowEx(0, 0, None, "I'm in back...")
# I'm just making the front button bigger so that it is obvious it is in front ...
front = Front(text="*____________________________*",whndl=whndl)
front.setWindowOpacity(0.8)
front.show()
a.exec_()
if __name__ == "__main__":
main()
self.setAttribute(Qt.WA_TransparentForMouseEvents, True)
self.setAttribute(Qt.WA_NoChildEventsForParent, True)
self.setWindowFlags(Qt.Window|Qt.X11BypassWindowManagerHint|Qt.WindowStaysOnTopHint|Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
This works. It is tested on Linux Mint 20.1 Cinnamon.
That means the parent blocked it WA_TransparentForMouseEvents all the time

wxpython systray icon menu

I'm designing an application that I want to run in the background. There isn't any user interaction necessary, so I want the app to run invisibly save for a systray icon. I want that icon to have a menu that just opens the config/help files in notepad. Could someone point me in the right direction or provide an example?
You can probably do this more cleanly but I have using some samples a while back I was able to create myself a class to handle the basic contruction of a taskbar icon.
TaskBarIcon.py
import wx
ID_SHOW_OPTION = wx.NewId()
ID_EDIT_OPTION = wx.NewId()
class Icon(wx.TaskBarIcon):
def __init__(self, parent, icon, tooltip):
wx.TaskBarIcon.__init__(self)
self.SetIcon(icon, tooltip)
self.parent = parent
self.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, self.OnLeftDClick)
self.CreateMenu()
def CreateMenu(self):
self.Bind(wx.EVT_TASKBAR_RIGHT_UP, self.OnPopup)
self.menu = wx.Menu()
self.menu.Append(ID_SHOW_OPTION, '&Show Option 1')
self.menu.Append(ID_EDIT_OPTION, '&Edit Option 2')
self.menu.AppendSeparator()
self.menu.Append(wx.ID_EXIT, 'E&xit')
def OnPopup(self, event):
self.PopupMenu(self.menu)
def OnLeftDClick(self, event):
if self.parent.IsIconized():
self.parent.Iconize(False)
if not self.parent.IsShown():
self.parent.Show(True)
self.parent.Raise()
Within your Frame's init(), add the two lines below:
self.TrayIcon = tbi.Icon(self, wx.Icon("C:\\YourIcon.png", wx.BITMAP_TYPE_PNG), "ToolTip Help Text Here")
self.Bind(wx.EVT_ICONIZE, self.OnIconify)
And now just add this function to your frame and you should be set:
def OnIconify(self, event):
self.Hide()
Just remember to edit the items in the Icon class to suit your needs.
Have you considered running this application as a windows service? Many users will consider a system tray icon with little to no functionality a nuisance. You could still provide links to help/config files as a start menu entry.
The python win32 extensions package should have support for python services.
Of course, there are still reasons why you may want to run this as a system tray icon. I'm sorry that I don't have any experience with that.
You want the wx.TaskBarIcon:
http://docs.wxwidgets.org/stable/wx_wxtaskbaricon.html
The wxPython Demo has example code you can look at.

How to embed some application window in my application using any Python GUI framework

I want some application to look like widget inside my Python application.
That's all. I dont need any interaction between them. I'm interested in solutions in any GUI toolkit for both windows and x windows.
It would be nice to have a solution with Tkinter but it's not crucial.
Using GTK on X windows (i.e. Linux, FreeBSD, Solaris), you can use the XEMBED protocol to embed widgets using gtk.Socket. Unfortunately, the application that you're launching has to explicitly support it so that you can tell it to embed itself. Some applications don't support this. Notably, I can't find a way to do it with Firefox.
Nonetheless, here's a sample program that will run either an X terminal or an Emacs session inside a GTK window:
import os
import gtk
from gtk import Socket, Button, Window, VBox, HBox
w = Window()
e = Button("Emacs")
x = Button("XTerm")
s = Socket()
v = VBox()
h = HBox()
w.add(v)
v.add(s)
h.add(e)
h.add(x)
v.pack_start(h, expand=False)
def runemacs(btn):
x.set_sensitive(False); e.set_sensitive(False)
os.spawnlp(os.P_NOWAIT, "emacs",
"emacs", "--parent-id", str(s.get_id()))
def runxterm(btn):
x.set_sensitive(False); e.set_sensitive(False)
os.spawnlp(os.P_NOWAIT, "xterm",
"xterm", "-into", str(s.get_id()))
e.connect('clicked', runemacs)
x.connect('clicked', runxterm)
w.show_all()
gtk.main()
Not enough reputation to comment on Glyphs answer. To make xterm work, in addition to the comments above one needs to also add
XTerm*allowSendEvents: True
to ~/.Xresources. (and perhaps reload those, with xrdb -load ~/.Xresources)

Categories

Resources